[
  {
    "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# temp\ntmp/\n\n# CMakeFiles\nCMakeFiles/\nCMakeLists.txt\nCMakeCache.txt\ncmake_install.cmake\ninstall_manifest.txt\nMakefile\n\n# idea project\n.idea\ncmake-build-debug\n\n*.dat\n\n\n.vscode/"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\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.\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"https://github.com/alibaba/nacos/blob/develop/doc/Nacos_Logo.png\" width=\"50%\" height=\"50%\" /> \n\n[中文版本说明请点这里](https://github.com/nacos-group/nacos-sdk-cpp/blob/master/README_zh_CN.md)\n\n# Nacos-sdk-cpp\n\nNacos-sdk-cpp for c++ client allows users to access Nacos service, it supports service discovery and dynamic configuration.\n\n\n[![Gitter](https://badges.gitter.im/alibaba/nacos.svg)](https://gitter.im/alibaba/nacos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)   [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n\n# Quick Examples\n## Setup project\nDownload the source and run the following command in bash:\n\n```\ncd nacos-sdk-cpp\ncmake .\nmake\n```\n\na libnacos-cli.so and a nacos-cli.out will be generated\n\nrun `./nacos-cli.out` to perform test on the library\n\nrun `make install` to install the libnacos-cli to your system library path\n\n**Note:** You need to run a nacos server on your local machine listening on port 8848 to go through the whole test\nOne of the testcases will test endpoint functionality, so **you also need** to run a simple http server on port 80 which provides the following content:\n\n`127.0.0.1:8848`\n\n**on path /nacos/endpoint0**\n\n**All these examples could be found in nacos-sdk-cpp/examples/**\n\n## Integrate the library into your project\n\nHere is an example showing how to integrate the library(.so) into your project:\n\nIntegratingIntoYourProject.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//Server address\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    NacosString ss = \"\";\n    try {\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n        return -1;\n    }\n    cout << ss << endl;\n\n    return 0;\n}\n\n```\n\n`g++ -I/usr/local/include/nacos/ IntegratingIntoYourProject.cpp -lnacos-cli -o integrated.out`\n\nStart a nacos on your localmachine listening on port 8848, and run `./integrated.out`\n\nThen you'll see:\n\n`SuccessfullyIntegrated`\n\n## If you are using a static lib(.a):\nAssume that the file you are compiling resides in the same directory as the .a library, please use the following command:\n\n`g++ -I/usr/local/include/nacos/ IntegratingIntoYourProject.cpp -lcurl -lz -L. -lnacos-cli-static -o integrated.out`\n\n-lcurl -lz Specifies the curl and lz library used by libnacos\n\n-L. -lnacos-cli-static links the static libnacos library resides in the same directory as IntegratingIntoYourProject.cpp\n\n## Configuration\n\n### Get Config\n\ngetConfig.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//Server address\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    NacosString ss = \"\";\n    try {\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n        return -1;\n    }\n    cout << ss << endl;\n\n    return 0;\n}\n``` \n\n### Publish Config\n\nsetConfig.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//server address\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    bool bSucc = false;\n    NacosString ss = \"\";\n\n    try {\n        bSucc = n->publishConfig(\"Cfg_key\", NULLSTR, \"Cfg_val\");\n        int retry = 0;\n        ss = n->getConfig(\"Cfg_key\", NULLSTR, 1000);\n        while (!(ss == \"Cfg_val\") && retry++ < 10) {\n            ss = n->getConfig(\"Cfg_key\", NULLSTR, 1000);\n        }\n\n        if (!(ss == \"Cfg_val\")) {\n            throw NacosException(0, \"getConfig() failed.\");\n        }\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n\n        return -1;\n    }\n    cout << \"Publishing Key:Cfg_key with value:Cfg_val result:\" << bSucc << endl;\n\n    return 0;\n}\n``` \n\n### Listen to key change & Cancel listening\n\nlistenToKeys.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyListener : public Listener {\nprivate:\n    int num;\npublic:\n    MyListener(int num) {\n        this->num = num;\n    }\n\n    void receiveConfigInfo(const NacosString &configInfo) {\n        cout << \"===================================\" << endl;\n        cout << \"Watcher\" << num << endl;\n        cout << \"Watched Key UPDATED:\" << configInfo << endl;\n        cout << \"===================================\" << endl;\n    }\n};\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n\n    MyListener *theListener = new MyListener(1);//You don't need to free it, since it will be deleted by the function removeListener\n    n->addListener(\"dqid\", NULLSTR, theListener);//All changes on the key dqid will be received by MyListener\n\n    cout << \"Input a character to continue\" << endl;\n    getchar();\n    cout << \"remove listener\" << endl;\n    n->removeListener(\"dqid\", NULLSTR, theListener);//Cancel listening\n    getchar();\n\n    return 0;\n}\n```\n\n## Naming\n\n### Register Instance & Unregister Instance\n\nregisterInstances.cpp:\n```C++\n#include <iostream>\n#include <unistd.h>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties configProps;\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(namingSvc);\n    Instance instance;\n    instance.clusterName = \"DefaultCluster\";\n    instance.ip = \"127.0.0.1\";\n    instance.port = 2333;\n    instance.instanceId = \"1\";\n    instance.ephemeral = true;\n\n    //Registers 5 services named TestNamingService1...5\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n            instance.port = 2000 + i;\n            namingSvc->registerInstance(serviceName, instance);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return -1;\n    }\n    sleep(30);\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n\n            namingSvc->deregisterInstance(serviceName, \"127.0.0.1\", 2000 + i);\n            sleep(1);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return -1;\n    }\n    sleep(30);\n\n    return 0;\n}\n```\n\n### Subscribe & Unsubscribe\n\nsubscribeServices.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyServiceListener : public EventListener {\nprivate:\n    int num;\npublic:\n    MyServiceListener(int num) {\n        this->num = num;\n    }\n\n    void receiveNamingInfo(const ServiceInfo &serviceInfo){\n        cout << \"===================================\" << endl;\n        cout << \"Watcher: \" << num << endl;\n        cout << \"Watched service UPDATED: \" << serviceInfo.toInstanceString() << endl;\n        cout << \"===================================\" << endl;\n\n    }\n};\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    //Interval for poller to check the status of subscribed services(unit:Ms), 30000 by default\n    //Here we set it to 5000 to see the output more quick\n    props[PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL] = \"5000\";\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    NamingService *n = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(n);\n\n    n->subscribe(\"ss\", new MyServiceListener(1));\n    cout << \"Press any key to register services\" << endl;\n    getchar();\n\n    n->registerInstance(\"ss\", \"127.0.0.1\", 33);\n    n->registerInstance(\"ss\", \"127.0.0.1\", 34);\n    cout << \"Press any key to deregister services\" << endl;\n    getchar();\n\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 33);\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 34);\n    cout << \"All instances Unregistered, press any key to finish testing\" << endl;\n    getchar();\n\n    return 0;\n}\n```\n\n### Get all instances of a service\n\ngetAllInstances.cpp:\n```C++\n#include <iostream>\n#include <list>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties configProps;\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService(namingSvc);\n\n    list <Instance> instances = namingSvc->getAllInstances(\"TestNamingService1\");\n    cout << \"getAllInstances from server:\" << endl;\n    for (list<Instance>::iterator it = instances.begin();\n         it != instances.end(); it++) {\n        cout << \"Instance:\" << it->toString() << endl;\n    }\n\n    return 0;\n}\n```\n\n### Enabling Authentication\n\nIf your Nacos server is secured with password, you can add the following snippet to any of the examples above to enable authentication:\n\n```C++\nusing namespace nacos;\n......\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::AUTH_USERNAME] = \"username\";\n    configProps[PropertyKeyConst::AUTH_PASSWORD] = \"password\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ConfigService *n = factory->CreateConfigService();\n    NamingService *namingSvc = factory->CreateNamingService();\n......\n```\n\n### Enabling SPAS Authentication\n\n```C++\nusing namespace nacos;\n......\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::ACCESS_KEY] = \"accessKey\";\n    configProps[PropertyKeyConst::SECRET_KEY] = \"secretKey\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ConfigService *n = factory->CreateConfigService();\n    NamingService *namingSvc = factory->CreateNamingService();\n......\n```\n\n# Supported System/Compilers\n\n| OS/Environment | Compilers | Tested version |\n| ---- | ---- | ---- |\n|MacOS Darwin 19.6.0 x86_64|Clang|Apple clang version 12.0.0 (clang-1200.0.26.2)|\n|Windows 10 WSL|GCC|version 4.8.4|\n|Windows 10 CYGWIN_NT-10.0 x86_64|GCC|version 10.2.0 (GCC)|\n|Ubuntu1~16.04.12|GCC|version 5.4.0|\n|CentOS|GCC||\n|Windows|Visual C++|To be done|\n\n\n# About Nacos\n\nNacos (official site: [http://nacos.io](http://nacos.io)) is an easy-to-use platform designed for dynamic service discovery and configuration and service management. It helps you to build cloud native applications and microservices platform easily.\n\nService is a first-class citizen in Nacos. Nacos supports almost all type of services, for example: [Dubbo/gRPC service](https://nacos.io/en-us/docs/use-nacos-with-dubbo.html), [Spring Cloud RESTFul service](https://nacos.io/en-us/docs/use-nacos-with-springcloud.html) and [Kubernetes service](https://nacos.io/en-us/docs/use-nacos-with-kubernetes.html).\n"
  },
  {
    "path": "README_zh_CN.md",
    "content": "<img src=\"https://github.com/alibaba/nacos/blob/develop/doc/Nacos_Logo.png\" width=\"50%\" height=\"50%\" />\n\n# Nacos-sdk-cpp\n\nNacos-sdk-cpp是nacos客戶端的C++版本，它支持服务发现和动态配置\n\n[![Gitter](https://badges.gitter.im/alibaba/nacos.svg)](https://gitter.im/alibaba/nacos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)   [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n\n# 快速开始\n## 设置工程\n下载工程源代码并且执行下述命令:\n\n```\ncd nacos-sdk-cpp\ncmake .\nmake\n```\n\n将会产生一个libnacos-cli.so 和一个 nacos-cli.out\n\n运行 `./nacos-cli.out` 以执行客户端的所有testcase\n\n运行 `make install` 将libnacos-cli安装到lib目录\n\n**注意:** 你需要在本机运行一个nacos server，监听8848端口以完成所有测试\n其中有个测试将会测试端点（endpoint）功能，**所以你还需要**在本机运行一个http服务器，在路径/endpoints/endpoint0提供下述内容：\n\n`127.0.0.1:8848`\n\n**这些例子你都能在nacos-sdk-cpp/examples/找到**\n\n## 将libnacos-cli集成到你的工程\n\n下面的例子说明了如何将库文件(.so) 集成到你的工程:\n\nIntegratingIntoYourProject.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//Server address\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    NacosString ss = \"\";\n    try {\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n        return -1;\n    }\n    cout << ss << endl;\n\n    return 0;\n}\n\n```\n\n`g++ -I/usr/local/include/nacos/ IntegratingIntoYourProject.cpp -lnacos-cli -o integrated.out`\n\n在本机的8848端口启动一个nacos server, 并且运行 `./integrated.out`\n\n你将会看到:\n\n`SuccessfullyIntegrated`\n\n## 如果你使用静态库(.a)链接\n假设.a文件和待编译文件在同一目录, 请执行下述命令:\n\n`g++ -I/usr/local/include/nacos/ IntegratingIntoYourProject.cpp -lcurl -lz -L. -lnacos-cli-static -o integrated.out`\n\n使用-lcurl -lz指定nacos客户端使用的curl和lz库\n\n使用-L. -lnacos-cli-static引用当前目录下的libnacos-cli-static.a\n\n## 配置\n\n### 获取配置\n\ngetConfig.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//Server address\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    NacosString ss = \"\";\n    try {\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n        return -1;\n    }\n    cout << ss << endl;\n\n    return 0;\n}\n``` \n\n### 发布配置\n\nsetConfig.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//server address\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    bool bSucc = false;\n    NacosString ss = \"\";\n\n    try {\n        bSucc = n->publishConfig(\"Cfg_key\", NULLSTR, \"Cfg_val\");\n        int retry = 0;\n        ss = n->getConfig(\"Cfg_key\", NULLSTR, 1000);\n        while (!(ss == \"Cfg_val\") && retry++ < 10) {\n            ss = n->getConfig(\"Cfg_key\", NULLSTR, 1000);\n        }\n\n        if (!(ss == \"Cfg_val\")) {\n            throw NacosException(0, \"getConfig() failed.\");\n        }\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n\n        return -1;\n    }\n    cout << \"Publishing Key:Cfg_key with value:Cfg_val result:\" << bSucc << endl;\n\n    return 0;\n}\n``` \n\n### 监听配置变化和取消监听\n\nlistenToKeys.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyListener : public Listener {\nprivate:\n    int num;\npublic:\n    MyListener(int num) {\n        this->num = num;\n    }\n\n    void receiveConfigInfo(const NacosString &configInfo) {\n        cout << \"===================================\" << endl;\n        cout << \"Watcher\" << num << endl;\n        cout << \"Watched Key UPDATED:\" << configInfo << endl;\n        cout << \"===================================\" << endl;\n    }\n};\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n\n    MyListener *theListener = new MyListener(1);//You don't need to free it, since it will be deleted by the function removeListener\n    n->addListener(\"dqid\", NULLSTR, theListener);//All changes on the key dqid will be received by MyListener\n\n    cout << \"Input a character to continue\" << endl;\n    getchar();\n    cout << \"remove listener\" << endl;\n    n->removeListener(\"dqid\", NULLSTR, theListener);//Cancel listening\n    getchar();\n\n    return 0;\n}\n```\n\n## 命名服务\n\n### 注册和反注册实例\n\nregisterInstances.cpp:\n```C++\n#include <iostream>\n#include <unistd.h>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties configProps;\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(namingSvc);\n    Instance instance;\n    instance.clusterName = \"DefaultCluster\";\n    instance.ip = \"127.0.0.1\";\n    instance.port = 2333;\n    instance.instanceId = \"1\";\n    instance.ephemeral = true;\n\n    //Registers 5 services named TestNamingService1...5\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n            instance.port = 2000 + i;\n            namingSvc->registerInstance(serviceName, instance);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return -1;\n    }\n    sleep(30);\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n\n            namingSvc->deregisterInstance(serviceName, \"127.0.0.1\", 2000 + i);\n            sleep(1);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return -1;\n    }\n    sleep(30);\n\n    return 0;\n}\n```\n\n### 订阅和取消订阅服务\n\nsubscribeServices.cpp:\n```C++\n#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyServiceListener : public EventListener {\nprivate:\n    int num;\npublic:\n    MyServiceListener(int num) {\n        this->num = num;\n    }\n\n    void receiveNamingInfo(const ServiceInfo &serviceInfo){\n        cout << \"===================================\" << endl;\n        cout << \"Watcher: \" << num << endl;\n        cout << \"Watched service UPDATED: \" << serviceInfo.toInstanceString() << endl;\n        cout << \"===================================\" << endl;\n\n    }\n};\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    //Interval for poller to check the status of subscribed services(unit:Ms), 30000 by default\n    //Here we set it to 5000 to see the output more quick\n    props[PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL] = \"5000\";\n    NacosServiceFactory *factory = new NacosServiceFactory(props);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    NamingService *n = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(n);\n\n    n->subscribe(\"ss\", new MyServiceListener(1));\n    cout << \"Press any key to register services\" << endl;\n    getchar();\n\n    n->registerInstance(\"ss\", \"127.0.0.1\", 33);\n    n->registerInstance(\"ss\", \"127.0.0.1\", 34);\n    cout << \"Press any key to deregister services\" << endl;\n    getchar();\n\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 33);\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 34);\n    cout << \"All instances Unregistered, press any key to finish testing\" << endl;\n    getchar();\n\n    return 0;\n}\n```\n\n### 获取某个服务的全部实例\n\ngetAllInstances.cpp:\n```C++\n#include <iostream>\n#include <list>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties configProps;\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ResourceGuard <NacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService(namingSvc);\n\n    list <Instance> instances = namingSvc->getAllInstances(\"TestNamingService1\");\n    cout << \"getAllInstances from server:\" << endl;\n    for (list<Instance>::iterator it = instances.begin();\n         it != instances.end(); it++) {\n        cout << \"Instance:\" << it->toString() << endl;\n    }\n\n    return 0;\n}\n```\n\n### 启用认证\n\n如果你的服务器启设置了密码，在上述任意一个例子当中加入下述配置，即可启用用户名密码认证：\n\n```C++\nusing namespace nacos;\n......\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::AUTH_USERNAME] = \"username\";\n    configProps[PropertyKeyConst::AUTH_PASSWORD] = \"password\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ConfigService *n = factory->CreateConfigService();\n    NamingService *namingSvc = factory->CreateNamingService();\n......\n```\n\n### 启动SPAS鉴权\n\n```C++\nusing namespace nacos;\n......\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::ACCESS_KEY] = \"accessKey\";\n    configProps[PropertyKeyConst::SECRET_KEY] = \"secretKey\";\n    NacosServiceFactory *factory = new NacosServiceFactory(configProps);\n    ConfigService *n = factory->CreateConfigService();\n    NamingService *namingSvc = factory->CreateNamingService();\n......\n```\n\n# 支持的系统/编译器\n\n| 操作系统/环境 | 编译器 | 测试版本 |\n| ---- | ---- | ---- |\n|MacOS Darwin 19.6.0 x86_64|Clang|Apple clang version 12.0.0 (clang-1200.0.26.2)|\n|Windows 10 WSL|GCC|version 4.8.4|\n|Windows 10 CYGWIN_NT-10.0 x86_64|GCC|version 10.2.0 (GCC)|\n|Ubuntu1~16.04.12|GCC|version 5.4.0|\n|CentOS|GCC||\n|Windows|Visual C++|计划中|\n\n# 关于Nacos\n\nNacos (官方网站: [http://nacos.io](http://nacos.io)) 是一个易用的动态服务发现、配置管理以及服务管理平台。它将助力您轻松建立云上原生应用和微服务。\n\n在Nacos中，服务是一级公民. Nacos 支持几乎所有种类的服务，例如：\n\n[Dubbo/gRPC service](https://nacos.io/en-us/docs/use-nacos-with-dubbo.html)\n\n[Spring Cloud RESTFul service](https://nacos.io/en-us/docs/use-nacos-with-springcloud.html)\n\n[Kubernetes service](https://nacos.io/en-us/docs/use-nacos-with-kubernetes.html).\n"
  },
  {
    "path": "examples/IntegratingIntoYourProject.cpp",
    "content": "#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//Server address\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    NacosString ss = \"\";\n    try {\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n        return -1;\n    }\n    cout << ss << endl;\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/generate_examples.sh",
    "content": "#!/bin/bash\n\ng++ -I/usr/local/include/nacos/ IntegratingIntoYourProject.cpp -lnacos-cli -o IntegratingIntoYourProject.out\ng++ -I/usr/local/include/nacos/ getAllInstances.cpp -lnacos-cli -o getAllInstances.out\ng++ -I/usr/local/include/nacos/ getConfig.cpp -lnacos-cli -o getConfig.out\ng++ -I/usr/local/include/nacos/ listenToKeys.cpp -lnacos-cli -o listenToKeys.out\ng++ -I/usr/local/include/nacos/ registerInstances.cpp -lnacos-cli -o registerInstances.out\ng++ -I/usr/local/include/nacos/ setConfig.cpp -lnacos-cli -o setConfig.out\ng++ -I/usr/local/include/nacos/ subscribeServices.cpp -lnacos-cli -o subscribeServices.out\n"
  },
  {
    "path": "examples/getAllInstances.cpp",
    "content": "#include <iostream>\n#include <list>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties configProps;\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService(namingSvc);\n\n    list <Instance> instances = namingSvc->getAllInstances(\"TestNamingService1\");\n    cout << \"getAllInstances from server:\" << endl;\n    for (list<Instance>::iterator it = instances.begin();\n         it != instances.end(); it++) {\n        cout << \"Instance:\" << it->toString() << endl;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/getConfig.cpp",
    "content": "#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//Server address\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    NacosString ss = \"\";\n    try {\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n        return -1;\n    }\n    cout << ss << endl;\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/listenToKeys.cpp",
    "content": "#include <iostream>\n#include \"Nacos.h\"\n#include <stdio.h>\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyListener : public Listener {\nprivate:\n    int num;\npublic:\n    MyListener(int num) {\n        this->num = num;\n    }\n\n    void receiveConfigInfo(const NacosString &configInfo) {\n        cout << \"===================================\" << endl;\n        cout << \"Watcher\" << num << endl;\n        cout << \"Watched Key UPDATED:\" << configInfo << endl;\n        cout << \"===================================\" << endl;\n    }\n};\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n\n    MyListener *theListener = new MyListener(1);//You don't need to free it, since it will be deleted by the function removeListener\n    n->addListener(\"dqid\", NULLSTR, theListener);//All changes on the key dqid will be received by MyListener\n\n    cout << \"Input a character to continue\" << endl;\n    getchar();\n    cout << \"remove listener\" << endl;\n    n->removeListener(\"dqid\", NULLSTR, theListener);//Cancel listening\n    getchar();\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/registerInstances.cpp",
    "content": "#include <iostream>\n#include <unistd.h>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties configProps;\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(namingSvc);\n    Instance instance;\n    instance.clusterName = \"DefaultCluster\";\n    instance.ip = \"127.0.0.1\";\n    instance.port = 2333;\n    instance.instanceId = \"1\";\n    instance.ephemeral = true;\n\n    //Registers 5 services named TestNamingService1...5\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n            instance.port = 2000 + i;\n            namingSvc->registerInstance(serviceName, instance);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return -1;\n    }\n    sleep(30);\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n\n            namingSvc->deregisterInstance(serviceName, \"127.0.0.1\", 2000 + i);\n            sleep(1);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return -1;\n    }\n    sleep(30);\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/setConfig.cpp",
    "content": "#include <iostream>\n#include \"Nacos.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";//server address\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    bool bSucc = false;\n    NacosString ss = \"\";\n\n    try {\n        bSucc = n->publishConfig(\"Cfg_key\", NULLSTR, \"Cfg_val\");\n        int retry = 0;\n        ss = n->getConfig(\"Cfg_key\", NULLSTR, 1000);\n        while (!(ss == \"Cfg_val\") && retry++ < 10) {\n            ss = n->getConfig(\"Cfg_key\", NULLSTR, 1000);\n        }\n\n        if (!(ss == \"Cfg_val\")) {\n            throw NacosException(0, \"getConfig() failed.\");\n        }\n    }\n    catch (NacosException &e) {\n        cout <<\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\n             \"Reason:\" << e.what() << endl;\n\n        return -1;\n    }\n    cout << \"Publishing Key:Cfg_key with value:Cfg_val result:\" << bSucc << endl;\n\n    return 0;\n}\n"
  },
  {
    "path": "examples/subscribeServices.cpp",
    "content": "#include <iostream>\n#include \"Nacos.h\"\n#include <stdio.h>\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyServiceListener : public EventListener {\nprivate:\n    int num;\npublic:\n    MyServiceListener(int num) {\n        this->num = num;\n    }\n\n    void receiveNamingInfo(const ServiceInfo &serviceInfo){\n        cout << \"===================================\" << endl;\n        cout << \"Watcher: \" << num << endl;\n        cout << \"Watched service UPDATED: \" << serviceInfo.toInstanceString() << endl;\n        cout << \"===================================\" << endl;\n\n    }\n};\n\nint main() {\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    //Interval for poller to check the status of subscribed services(unit:Ms), 30000 by default\n    //Here we set it to 5000 to see the output more quick\n    props[PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL] = \"5000\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *n = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(n);\n\n    n->subscribe(\"ss\", new MyServiceListener(1));\n    cout << \"Press any key to register services\" << endl;\n    getchar();\n\n    n->registerInstance(\"ss\", \"127.0.0.1\", 33);\n    n->registerInstance(\"ss\", \"127.0.0.1\", 34);\n    cout << \"Press any key to deregister services\" << endl;\n    getchar();\n\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 33);\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 34);\n    cout << \"All instances Unregistered, press any key to finish testing\" << endl;\n    getchar();\n\n    return 0;\n}\n"
  },
  {
    "path": "include/Compatibility.h",
    "content": "//\n// Created by liuhanyu on 2021/4/7.\n// Compatibility header\n\n#ifndef NACOS_SDK_CPP_COMPATIBILITY_H\n#define NACOS_SDK_CPP_COMPATIBILITY_H\n\n#if __cplusplus >= 201402L\n//C++ 17 compatibility\n#define NACOS_THROW(...)\n#define NACOS_NOTHROW() noexcept\n#else\n#define NACOS_THROW throw\n#define NACOS_NOTHROW throw\n#endif\n\n#endif //NACOS_SDK_CPP_COMPATIBILITY_H\n"
  },
  {
    "path": "include/Nacos.h",
    "content": "/*\n * Copyright 1999-2020 Alibaba Group Holding Ltd.\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.\n */\n#ifndef _NACOS_H_\n\n#define _NACOS_H_\n#include \"factory/INacosServiceFactory.h\"\n#include \"factory/NacosFactoryFactory.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"ResourceGuard.h\"\n\n#endif"
  },
  {
    "path": "include/NacosExceptions.h",
    "content": "#ifndef __NACOS_EXCEPTIONS_H_\r\n#define __NACOS_EXCEPTIONS_H_\r\n\r\n#include <exception>\r\n#include \"NacosString.h\"\r\n#include \"Compatibility.h\"\r\n\r\nnamespace nacos{\r\nclass NacosException : public std::exception {\r\nprotected:\r\n    int _errcode;\r\n    NacosString _errmsg;\r\npublic:\r\n    NacosException(int errorcode, const char *errormsg) NACOS_NOTHROW();\r\n\r\n    NacosException(int errorcode, const NacosString &errormsg) NACOS_NOTHROW();\r\n\r\n    ~NacosException() NACOS_NOTHROW() {};\r\n\r\n    const char *what() const NACOS_NOTHROW() { return _errmsg.c_str(); };\r\n\r\n    const int errorcode() const NACOS_NOTHROW() { return _errcode; };\r\n\r\n    static const int CLIENT_INVALID_PARAM = -400;\r\n    /**\r\n    * over client threshold（超过server端的限流阈值）\r\n    */\r\n    static const int CLIENT_OVER_THRESHOLD = -503;\r\n\r\n    /**\r\n    * server error code\r\n    * 400 403 throw exception to user\r\n    * 500 502 503 change ip and retry\r\n    */\r\n\r\n    /**\r\n    * invalid param（参数错误）\r\n    */\r\n    static const int INVALID_PARAM = 400;\r\n    /**\r\n    * no right（鉴权失败）\r\n    */\r\n    static const int NO_RIGHT = 403;\r\n\r\n    static const int HTTP_NOT_FOUND = 404;\r\n\r\n    /**\r\n    * conflict（写并发冲突）\r\n    */\r\n    static const int CONFLICT = 409;\r\n    /**\r\n    * server error（server异常，如超时）\r\n    */\r\n    static const int SERVER_ERROR = 500;\r\n    /**\r\n    * bad gateway（路由异常，如nginx后面的Server挂掉）\r\n    */\r\n    static const int BAD_GATEWAY = 502;\r\n    /**\r\n    * over threshold（超过server端的限流阈值）\r\n    */\r\n    static const int OVER_THRESHOLD = 503;\r\n\r\n    /**\r\n    * Error while parsing the JSON string\r\n    */\r\n    static const int INVALID_JSON_FORMAT = 100001;\r\n\r\n    /**\r\n    * One or more JSON field is missing\r\n    */\r\n    static const int LACK_JSON_FIELD = 100002;\r\n\r\n    static const int MALFORMED_CONFIG_FILE = 1001;\r\n    static const int FILE_NOT_FOUND = 1002;\r\n    static const int INVALID_FACTORY_CONFIG = 1003;\r\n    static const int ALL_SERVERS_TRIED_AND_FAILED = 1004;\r\n    static const int NO_SERVER_AVAILABLE = 1005;\r\n    static const int INVALID_LOGIN_CREDENTIAL = 1006;\r\n    static const int UNABLE_TO_OPEN_FILE = 1007;\r\n    static const int UNABLE_TO_GET_HOST_IP = 1008;\r\n    static const int UNABLE_TO_CREATE_SOCKET = 1009;\r\n    static const int INVALID_CONFIG_PARAM = 1010;\r\n    static const int UNABLE_TO_GET_HOST_NAME = 1011;\r\n\r\n};\r\n\r\nclass NetworkException : public std::exception {\r\nprivate:\r\n    int _curlerrcode;\r\n    NacosString _errmsg;\r\npublic:\r\n    NetworkException(int errorcode, const char *errormsg) NACOS_NOTHROW(): _curlerrcode(errorcode), _errmsg(errormsg) {};\r\n\r\n    NetworkException(int errorcode, const NacosString &errormsg) NACOS_NOTHROW(): _curlerrcode(errorcode), _errmsg(errormsg) {};\r\n\r\n    ~NetworkException() NACOS_NOTHROW() {};\r\n\r\n    const char *what() const NACOS_NOTHROW() { return _errmsg.c_str(); };\r\n\r\n    const int errorcode() const NACOS_NOTHROW() { return _curlerrcode; };\r\n};\r\n\r\nclass IOException : public NacosException {\r\npublic:\r\n    IOException(int errorcode, const char *errormsg) NACOS_NOTHROW() : NacosException(errorcode, errormsg) {};\r\n\r\n    IOException(int errorcode, const NacosString &errormsg) NACOS_NOTHROW() : NacosException(errorcode, errormsg) {};\r\n\r\n    ~IOException() NACOS_NOTHROW() {};\r\n};\r\n\r\nclass MalformedConfigException : public NacosException {\r\npublic:\r\n    MalformedConfigException(const NacosString &file, const NacosString &detailedMsg) : NacosException(NacosException::MALFORMED_CONFIG_FILE,\r\n                                                                       \"Malformed Config file:\" + file + \" reason:\" + detailedMsg) {};\r\n};\r\n\r\nclass InvalidFactoryConfigException : public NacosException {\r\npublic:\r\n    InvalidFactoryConfigException() : NacosException(NacosException::INVALID_FACTORY_CONFIG,\r\n                                                     \"Either config file or property should be configed.\") {};\r\n};\r\n}//namespace nacos\r\n\r\n#endif\r\n"
  },
  {
    "path": "include/NacosString.h",
    "content": "#ifndef __NACOS_STRING_H_\r\n#define __NACOS_STRING_H_\r\n\r\n#include <string>\r\n#include <sstream>\r\n\r\n#define NacosString std::string\r\n#define NULLSTR NacosStringOps::nullstr\r\n#define isNull NacosStringOps::isNullStr\r\n\r\nnamespace nacos{\r\nclass NacosStringOps {\r\npublic:\r\n    static const NacosString nullstr;\r\n\r\n    static bool isNullStr(const NacosString &str);\r\n\r\n    template<typename T>\r\n    static NacosString valueOf(T val);\r\n\r\n    static const NacosString STR_TRUE;\r\n    static const NacosString STR_FALSE;\r\n};\r\n\r\ntemplate<typename T>\r\nNacosString NacosStringOps::valueOf(T val) {\r\n    std::ostringstream os;\r\n    if (os << val) {\r\n        return NacosString(os.str().c_str());\r\n    }\r\n\r\n    return NULLSTR;\r\n}\r\n\r\ntemplate<>\r\nNacosString NacosStringOps::valueOf<bool>(bool val);\r\n\r\n}//namespace nacos\r\n\r\n#endif\r\n"
  },
  {
    "path": "include/Properties.h",
    "content": "#ifndef __PROPERTIES_H_\r\n#define __PROPERTIES_H_\r\n\r\n#include <map>\r\n#include \"NacosString.h\"\r\n\r\nnamespace nacos{\r\nclass Properties : public std::map<NacosString, NacosString> {\r\npublic:\r\n    NacosString toString() const {\r\n        NacosString content = \"\";\r\n        for (std::map<NacosString, NacosString>::const_iterator it = begin(); it != end(); it++) {\r\n            content += (it->first + \"=\" + it->second + \"\\n\");\r\n        }\r\n        return content;\r\n    }\r\n\r\n    bool contains(const NacosString &key) const {\r\n        if (count(key) > 0) {\r\n            return true;\r\n        }\r\n\r\n        return false;\r\n    }\r\n};\r\n}//namespace nacos\r\n\r\n#endif"
  },
  {
    "path": "include/ResourceGuard.h",
    "content": "//\n// Created by liuhanyu on 2020/9/6.\n//\n\n#ifndef NACOS_SDK_CPP_RESOURCEGUARD_H\n#define NACOS_SDK_CPP_RESOURCEGUARD_H\n\nnamespace nacos{\ntemplate<typename T>\nclass ResourceGuard {\nprivate:\n    T *_obj;//The object being watched\n    ResourceGuard();\n\npublic:\n    ResourceGuard(T *obj) { _obj = obj; };\n\n    ~ResourceGuard() {\n        if (_obj != NULL) {\n            delete _obj;\n            _obj = NULL;\n        }\n    };\n};\n}//namespace nacos\n\n\n#endif //NACOS_SDK_CPP_RESOURCEGUARD_H\n"
  },
  {
    "path": "include/config/ConfigService.h",
    "content": "#ifndef __CFG_SVC_H_\r\n#define __CFG_SVC_H_\r\n\r\n#include \"NacosExceptions.h\"\r\n#include \"NacosString.h\"\r\n#include \"listen/Listener.h\"\r\n#include \"Compatibility.h\"\r\nnamespace nacos{\r\nclass ConfigService {\r\npublic:\r\n    /**\r\n     * Get config\r\n     *\r\n     * @param dataId    dataId\r\n     * @param group     group\r\n     * @param timeoutMs read timeout\r\n     * @return config value\r\n     * @throws NacosException NacosException\r\n     */\r\n    virtual NacosString\r\n    getConfig(const NacosString &dataId, const NacosString &group, long timeoutMs) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Add a listener to the configuration, after the server modified the\r\n     * configuration, the client will use the incoming listener callback.\r\n     * Recommended asynchronous processing, the application can implement the\r\n     * getExecutor method in the ManagerListener, provide a thread pool of\r\n     * execution. If provided, use the main thread callback, May block other\r\n     * configurations or be blocked by other configurations.\r\n     *\r\n     * @param dataId   dataId\r\n     * @param group    group\r\n     * @param listener listener\r\n     * @throws NacosException NacosException\r\n     */\r\n    virtual void\r\n    addListener(const NacosString &dataId, const NacosString &group, Listener *listener) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Publish config.\r\n     *\r\n     * @param dataId  dataId\r\n     * @param group   group\r\n     * @param content content\r\n     * @return Whether publish\r\n     * @throws NacosException NacosException\r\n     */\r\n    virtual bool publishConfig(const NacosString &dataId, const NacosString &group,\r\n                               const NacosString &content) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Remove config\r\n     *\r\n     * @param dataId dataId\r\n     * @param group  group\r\n     * @return whether remove\r\n     * @throws NacosException NacosException\r\n     */\r\n    virtual bool removeConfig(const NacosString &dataId, const NacosString &group) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Remove listener\r\n     *\r\n     * @param listener listener\r\n     */\r\n    virtual void removeListener(const NacosString &dataId, const NacosString &group, Listener *listener) = 0;\r\n\r\n    /**\r\n     * Get server status\r\n     *\r\n     * @return whether health\r\n     */\r\n    //virtual NacosString getServerStatus() = 0;\r\n\r\n    virtual ~ConfigService() {};\r\n};\r\n}//namespace nacos\r\n#endif"
  },
  {
    "path": "include/constant/ConfigConstant.h",
    "content": "#ifndef __CONFIG_CONSTANTS_H_\n#define __CONFIG_CONSTANTS_H_\n\n#include \"NacosString.h\"\n\n/**\n * Constant\n *\n * @author Nacos\n */\n\nnamespace nacos{\n\n//Constants for config service\nclass ConfigConstant {\npublic:\n\n    const static NacosString DEFAULT_GROUP;\n\n    const static NacosString DEFAULT_CONTEXT_PATH;\n\n    const static NacosString PROTOCOL_VERSION;\n\n    const static NacosString GET_SERVERS_PATH;\n\n    const static NacosString DATAID;\n\n    const static NacosString PROBE_MODIFY_REQUEST;\n\n    const static NacosString PROBE_MODIFY_RESPONSE;\n\n    const static NacosString BASE_PATH;\n\n    const static NacosString CONFIG_CONTROLLER_PATH;\n\n    /**\n     * second\n     */\n    const static int POLLING_INTERVAL_TIME;\n\n    const static NacosString ENCODE;\n\n    const static int FLOW_CONTROL_THRESHOLD;\n\n    const static NacosString LINE_SEPARATOR;\n\n    const static NacosString WORD_SEPARATOR;\n\n    const static NacosString NAMING_INSTANCE_ID_SPLITTER;\n\n    const static NacosString DEFAULT_CLUSTER_NAME;\n\n    const static NacosString SERVICE_INFO_SPLITER;\n\n    const static NacosString FILE_SEPARATOR;\n\n    const static NacosString CONFIG_NEXT_LINE;\n\n    const static NacosString CONFIG_KV_SEPARATOR;\n\n    const static NacosString DEFAULT_CONFIG_FILE;\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "include/constant/NamingConstant.h",
    "content": "#ifndef __NAMING_CONSTANT_H_\n#define __NAMING_CONSTANT_H_\n\n#include \"NacosString.h\"\n\nnamespace nacos{\nclass NamingConstant {\npublic:\n    static const NacosString SERVICE_NAME;\n\n    static const NacosString CLUSTER_NAME;\n    static const NacosString UDP_PORT;\n    static const NacosString CLUSTERS;\n    static const NacosString CLIENT_IP;\n    static const NacosString HEALTHY_ONLY;\n\n    static const NacosString HEALTHY;\n\n    static const NacosString NAMESPACE_ID;\n\n    static const NacosString GROUP_NAME;\n\n    static const NacosString SPLITER;\n\n    static const NacosString EMPTY;\n\n    static const NacosString ALL_IPS;\n\n    static const NacosString BEAT;\n\n    static const NacosString PAGE_SIZE;\n    static const NacosString PAGE_NO;\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "include/constant/PropertyKeyConst.h",
    "content": "#ifndef __PROP_KEY_CONST_H_\n#define __PROP_KEY_CONST_H_\n\n#include \"NacosString.h\"\n\nnamespace nacos{\nclass PropertyKeyConst {\npublic:\n    static const NacosString IS_USE_ENDPOINT_PARSING_RULE;\n\n    static const NacosString ENDPOINT;\n\n    static const NacosString ENDPOINT_PORT;\n\n    static const NacosString NAMESPACE;\n\n    static const NacosString ENDPOINT_QUERY_PARAMS;\n\n    static const NacosString ACCESS_KEY;\n\n    static const NacosString SECRET_KEY;\n\n    static const NacosString APP_NAME;\n\n    static const NacosString RAM_ROLE_NAME;\n\n    static const NacosString SERVER_ADDR;\n\n    static const NacosString CONTEXT_PATH;\n\n    static const NacosString ENDPOINT_CONTEXT_PATH;\n\n    static const NacosString CLUSTER_NAME;\n\n    static const NacosString ENCODE;\n\n    static const NacosString NAMING_LOAD_CACHE_AT_START;\n\n    static const NacosString NAMING_CLIENT_BEAT_THREAD_COUNT;\n\n    static const NacosString NAMING_POLLING_THREAD_COUNT;\n\n    static const NacosString SRVLISTMGR_REFRESH_INTERVAL;\n\n    static const NacosString SERVER_REQ_TIMEOUT;\n\n    static const NacosString SUBSCRIPTION_POLL_INTERVAL;\n\n    static const NacosString CONFIG_LONGPULLLING_TIMEOUT;\n\n    static const NacosString HB_FAIL_WAIT_TIME;\n\n    static const NacosString NACOS_SNAPSHOT_PATH;\n\n    static const NacosString LOG_PATH;\n    static const NacosString LOG_ROTATE_SIZE;\n    static const NacosString LOG_LEVEL;\n\n    static const NacosString CLIENT_NAME;\n    static const NacosString AUTH_USERNAME;\n    static const NacosString AUTH_PASSWORD;\n    static const NacosString LOCAL_IP;\n    static const NacosString UDP_RECEIVER_PORT;\n\n    static const int NACOS_DEFAULT_PORT = 8848;\n\n    static const NacosString INSTANCE_ID_SEQ_FILE;\n\n    static const NacosString INSTANCE_ID_PREFIX;\n\n    /*public static class SystemEnv {\n\n        static const NacosString ALIBABA_ALIWARE_ENDPOINT_PORT = \"ALIBABA_ALIWARE_ENDPOINT_PORT\";\n\n        static const NacosString ALIBABA_ALIWARE_NAMESPACE = \"ALIBABA_ALIWARE_NAMESPACE\";\n\n        static const NacosString ALIBABA_ALIWARE_ENDPOINT_URL = \"ALIBABA_ALIWARE_ENDPOINT_URL\";\n    }*/\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "include/constant/UtilAndComs.h",
    "content": "#ifndef __UTIL_N_COMS_H_\n#define __UTIL_N_COMS_H_\n\n#include \"NacosString.h\"\n\nnamespace nacos{\nclass UtilAndComs {\npublic:\n    static NacosString VERSION;\n\n    static NacosString ENCODING;\n\n    static NacosString NACOS_URL_BASE;\n    \n    static NacosString NACOS_URL_INSTANCE;\n\n    static int REQUEST_DOMAIN_RETRY_COUNT;\n\n    static NacosString SERVER_ADDR_IP_SPLITER;\n\n    static int DEFAULT_CLIENT_BEAT_THREAD_COUNT;//TODO:Calc this according to nr_processors of the host\n\n    static int DEFAULT_POLLING_THREAD_COUNT;//TODO:Calc this according to nr_processors of the host\n\n    static void Init();\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "include/factory/INacosServiceFactory.h",
    "content": "//\n// Created by liuhanyu on 2020/8/30.\n//\n\n#ifndef NACOS_SDK_CPP_INACOSSERVICEFACTORY_H\n#define NACOS_SDK_CPP_INACOSSERVICEFACTORY_H\n\n#include \"naming/NamingService.h\"\n#include \"naming/NamingMaintainService.h\"\n#include \"config/ConfigService.h\"\n#include \"Properties.h\"\n\nnamespace nacos{\nclass INacosServiceFactory {\npublic:\n    virtual void setConfig(const NacosString &_configFile) = 0;\n\n    virtual void setProps(Properties &_props) = 0;\n\n    virtual NamingService *CreateNamingService() = 0;\n\n    virtual ConfigService *CreateConfigService() = 0;\n\n    virtual NamingMaintainService *CreateNamingMaintainService() = 0;\n\n    virtual ~INacosServiceFactory() {};\n};\n\n}//namespace nacos\n\n#endif //NACOS_SDK_CPP_INACOSSERVICEFACTORY_H\n"
  },
  {
    "path": "include/factory/NacosFactoryFactory.h",
    "content": "#ifndef NACOS_FACTORY_FACTORY_H\n#define NACOS_FACTORY_FACTORY_H\n#include \"factory/INacosServiceFactory.h\"\nnamespace nacos {\nclass NacosFactoryFactory {\npublic:\n    static INacosServiceFactory *getNacosFactory(const NacosString &_configFile);\n    static INacosServiceFactory *getNacosFactory(Properties &_props);\n};\n}\n#endif"
  },
  {
    "path": "include/listen/Listener.h",
    "content": "#ifndef __LISTENER_H_\r\n#define __LISTENER_H_\r\n\r\n#include \"NacosString.h\"\r\n#include \"thread/AtomicInt.h\"\r\n\r\nnamespace nacos{\r\nclass Listener {\r\nprivate:\r\n    NacosString listenerName;\r\n    AtomicInt<int> refCount;\r\npublic:\r\n    Listener() {\r\n        this->listenerName = \"theListener\";\r\n    };\r\n\r\n    int incRef() { return refCount.inc(); };\r\n\r\n    int decRef() { return refCount.dec(); };\r\n\r\n    int refCnt() const { return refCount.get(); };\r\n\r\n    void setListenerName(const NacosString &name) { this->listenerName = name; };\r\n\r\n    NacosString getListenerName() const { return listenerName; };\r\n\r\n    virtual void receiveConfigInfo(const NacosString &configInfo) = 0;\r\n\r\n    virtual ~Listener() {};\r\n};\r\n}//namespace nacos\r\n\r\n#endif"
  },
  {
    "path": "include/naming/ChangeAdvice.h",
    "content": "#ifndef __CHG_ADVICE_H_\n#define __CHG_ADVICE_H_\n\n#include \"NacosString.h\"\n#include \"naming/ServiceInfo.h\"\n\n//The wrapper class for service change information\nnamespace nacos{\nclass ChangeAdvice {\npublic:\n    bool added;//indicates Instance is added\n    bool removed;//indicates Instance is removed\n    bool modified;//indicates Instance is modified\n    //std::list<Instance> addedInstances;\n    //std::list<Instance> removedInstances;\n    //std::list<Instance> modifiedInstances;\n    //ServiceInfo oldServiceInfo;\n    ServiceInfo newServiceInfo;\n    NacosString key;\npublic:\n    ChangeAdvice();\n    ~ChangeAdvice();\n    static void compareChange(ServiceInfo &oldInfo, ServiceInfo &newInfo, ChangeAdvice &changeAdvice);\n    NacosString toString();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "include/naming/Cluster.h",
    "content": "#ifndef __CLUSTER_H_\n#define __CLUSTER_H_\n\n#include <map>\n#include \"NacosString.h\"\n\nnamespace nacos{\nclass HealthChecker {\nprivate:\n    NacosString type;\npublic:\n    NacosString getType() const { return type; };\n    void setType(const NacosString &_type) { type = _type; };\n};\nclass Cluster {\nprivate:\n    NacosString name;\n    HealthChecker healthChecker;\n    std::map<NacosString, NacosString> metadata;\npublic:\n    NacosString getName() const;\n\n    void setName(const NacosString &name);\n\n    HealthChecker getHealthChecker() const;\n\n    void setHealthChecker(const HealthChecker &healthChecker);\n\n    std::map<NacosString, NacosString> getMetadata() const;\n\n    void setMetadata(const std::map<NacosString, NacosString> &metadata);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "include/naming/Instance.h",
    "content": "#ifndef __INSTANCE_H_\r\n#define __INSTANCE_H_\r\n\r\n#include <map>\r\n#include \"NacosString.h\"\r\n\r\nnamespace nacos{\r\n\r\n//a service instance\r\nclass Instance {\r\npublic:\r\n    Instance & operator = (const Instance &rhs);\r\n    bool operator == (const Instance &rhs) const;\r\n    bool operator != (const Instance &rhs) const;\r\n\r\n    Instance();\r\n\r\n    /**\r\n    * unique id of this instance.\r\n    */\r\n    NacosString instanceId;\r\n\r\n    /**\r\n    * instance ip\r\n    */\r\n    NacosString ip;\r\n\r\n    /**\r\n    * instance port\r\n    */\r\n    int port;\r\n\r\n    /**\r\n    * instance weight\r\n    */\r\n    double weight;\r\n\r\n    /**\r\n    * instance health status\r\n    */\r\n    bool healthy;\r\n\r\n    /**\r\n    * If instance is enabled to accept request\r\n    */\r\n    bool enabled;\r\n\r\n    /**\r\n    * If instance is ephemeral\r\n    *\r\n    * @since 1.0.0\r\n    */\r\n    bool ephemeral;\r\n\r\n    /**\r\n    * cluster information of instance\r\n    */\r\n    NacosString clusterName;\r\n\r\n    /**\r\n    * Service information of instance\r\n    */\r\n    NacosString serviceName;\r\n\r\n    NacosString groupName;\r\n\r\n    NacosString namespaceId;\r\n\r\n    /**\r\n    * user extended attributes\r\n    */\r\n    std::map <NacosString, NacosString> metadata;\r\n\r\n    NacosString toString() const;\r\n    NacosString toInetAddr();\r\n};\r\n}//namespace nacos\r\n\r\n#endif"
  },
  {
    "path": "include/naming/ListView.h",
    "content": "#ifndef __NACOS_LIST_VUE_H_\n#define __NACOS_LIST_VUE_H_\n\n#include <list>\n#include \"NacosString.h\"\n\nnamespace nacos{\ntemplate <typename T>\nclass ListView{\nprivate:\n    int count;\n    std::list<T> data;\npublic:\n    ListView() { count = 0; };\n    int getCount() const { return count; };\n    std::list<T> getData() const { return data; };\n    void setCount(int _count) { count = _count; };\n    void setData(const std::list<T> &_data) { data = _data; };\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "include/naming/NamingMaintainService.h",
    "content": "#ifndef __NAM_MAINTN_SVC_H_\n#define __NAM_MAINTN_SVC_H_\n\n#include <list>\n#include \"naming/Instance.h\"\n#include \"naming/ServiceInfo2.h\"\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"ListView.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass NamingMaintainService {\npublic:\n    virtual bool updateInstance(const NacosString &serviceName, const NacosString & groupName, const Instance &instance) NACOS_THROW(NacosException) = 0;\n    virtual ServiceInfo2 queryService(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException) = 0;\n    virtual bool createService(const ServiceInfo2 &service, naming::Selector *selector) NACOS_THROW(NacosException) = 0;\n    virtual bool deleteService(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException) = 0;\n    virtual bool updateService(const ServiceInfo2 &service, naming::Selector *selector) NACOS_THROW(NacosException) = 0;\n    virtual ~NamingMaintainService() {};\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "include/naming/NamingService.h",
    "content": "#ifndef __NAM_SVC_H_\r\n#define __NAM_SVC_H_\r\n\r\n#include <list>\r\n#include \"naming/Instance.h\"\r\n#include \"naming/selectors/Selector.h\"\r\n#include \"naming/subscribe/EventListener.h\"\r\n#include \"NacosString.h\"\r\n#include \"NacosExceptions.h\"\r\n#include \"ListView.h\"\r\n#include \"Compatibility.h\"\r\n\r\nnamespace nacos{\r\nclass NamingService {\r\npublic:\r\n    /**\r\n     * register a instance to service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void\r\n    registerInstance(const NacosString &serviceName, const NacosString &ip, int port) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * register a instance to service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void registerInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip,\r\n                                  int port) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * register a instance to service with specified cluster name\r\n     *\r\n     * @param serviceName name of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @param clusterName instance cluster name\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void registerInstance(const NacosString &serviceName, const NacosString &ip, int port,\r\n                                  const NacosString &clusterName) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * register a instance to service with specified cluster name\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @param clusterName instance cluster name\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void\r\n    registerInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip, int port,\r\n                     const NacosString &clusterName) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * register a instance to service with specified instance properties\r\n     *\r\n     * @param serviceName name of service\r\n     * @param instance    instance to register\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void registerInstance(const NacosString &serviceName, Instance &instance) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * register a instance to service with specified instance properties\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param instance    instance to register\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void registerInstance(const NacosString &serviceName, const NacosString &groupName,\r\n                                  Instance &instance) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * deregister instance from a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void\r\n    deregisterInstance(const NacosString &serviceName, const NacosString &ip, int port) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * deregister instance from a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void deregisterInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip,\r\n                                    int port) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * deregister instance with specified cluster name from a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @param clusterName instance cluster name\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void deregisterInstance(const NacosString &serviceName, const NacosString &ip, int port,\r\n                                    const NacosString &clusterName) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * deregister instance with specified cluster name from a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param ip          instance ip\r\n     * @param port        instance port\r\n     * @param clusterName instance cluster name\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void\r\n    deregisterInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip, int port,\r\n                       const NacosString &clusterName) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * deregister instance with full instance information\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param instance    instance information\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void deregisterInstance(const NacosString &serviceName, const NacosString &groupName,\r\n                                    Instance &instance) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * get all instances of a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @return A list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual std::list <Instance> getAllInstances(const NacosString &serviceName) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * get all instances of a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @return A list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual std::list <Instance>\r\n    getAllInstances(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Get all instances within specified clusters of a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    list of cluster\r\n     * @return A list of qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual std::list <Instance>\r\n    getAllInstances(const NacosString &serviceName, const std::list <NacosString> &clusters) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Get all instances within specified clusters of a service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    list of cluster\r\n     * @return A list of qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual std::list <Instance> getAllInstances(const NacosString &serviceName, const NacosString &groupName,\r\n                                                 const std::list <NacosString> &clusters) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n    * Get instances with the predicate specified\r\n    *\r\n    * @param serviceName name of service\r\n    * @param groupName   group of service\r\n    * @param clusters    list of cluster\r\n    * @param predicate   predicate to filter instances\r\n    * @return A list of qualified instance\r\n    * @throw (NacosException) = 0\r\n    */\r\n    virtual std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName, const NacosString &groupName,\r\n                                                         const std::list <NacosString> &clusters,\r\n                                                         nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Get instances with the predicate specified\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    list of cluster\r\n     * @param predicate   predicate to filter instances\r\n     * @return A list of qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName,\r\n                                                         const std::list <NacosString> &clusters,\r\n                                                         nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n    * Get instances with the predicate specified\r\n    *\r\n    * @param serviceName name of service\r\n    * @param groupName   group of service\r\n    * @param predicate   predicate to filter instances\r\n    * @return A list of qualified instance\r\n    * @throw (NacosException) = 0\r\n    */\r\n    virtual std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName, const NacosString &groupName,\r\n                                                         nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n    * Get instances with the predicate specified\r\n    *\r\n    * @param serviceName name of service\r\n    * @param predicate   predicate to filter instances\r\n    * @return A list of qualified instance\r\n    * @throw (NacosException) = 0\r\n    */\r\n    virtual std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName, nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, bool healthy) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, const NacosString &groupName, bool healthy) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @param subscribe   if subscribe the service\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, bool healthy, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @param subscribe   if subscribe the service\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, const NacosString &groupName, bool healthy, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances within specified clusters of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    list of cluster\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, std::list<NacosString> clusters, bool healthy) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances within specified clusters of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    list of cluster\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, const NacosString &groupName, std::list<NacosString> clusters, bool healthy) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances within specified clusters of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    list of cluster\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @param subscribe   if subscribe the service\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, std::list<NacosString> clusters, bool healthy, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get qualified instances within specified clusters of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    list of cluster\r\n     * @param healthy     a flag to indicate returning healthy or unhealthy instances\r\n     * @param subscribe   if subscribe the service\r\n     * @return A qualified list of instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<Instance> selectInstances(const NacosString &serviceName, const NacosString &groupName, std::list<NacosString> clusters, bool healthy, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, const NacosString &groupName) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param subscribe   if subscribe the service\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param subscribe   if subscribe the service\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, const NacosString &groupName, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    a list of clusters should the instance belongs to\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, std::list<NacosString> clusters) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    a list of clusters should the instance belongs to\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, const NacosString &groupName, std::list<NacosString> clusters) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    a list of clusters should the instance belongs to\r\n     * @param subscribe   if subscribe the service\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, std::list<NacosString> clusters, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Select one healthy instance of service using predefined load balance strategy\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    a list of clusters should the instance belongs to\r\n     * @param subscribe   if subscribe the service\r\n     * @return qualified instance\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual Instance selectOneHealthyInstance(const NacosString &serviceName, const NacosString &groupName, std::list<NacosString> clusters, bool subscribe) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Subscribe service to receive events of instances alteration\r\n     *\r\n     * @param serviceName name of service\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void subscribe(const NacosString &serviceName, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Subscribe service to receive events of instances alteration\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void subscribe(const NacosString &serviceName, const NacosString &groupName, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Subscribe service to receive events of instances alteration\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    list of cluster\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void subscribe(const NacosString &serviceName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Subscribe service to receive events of instances alteration\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    list of cluster\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void subscribe(const NacosString &serviceName, const NacosString &groupName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Unsubscribe event listener of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void unsubscribe(const NacosString &serviceName, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * unsubscribe event listener of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void unsubscribe(const NacosString &serviceName, const NacosString &groupName, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Unsubscribe event listener of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param clusters    list of cluster\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void unsubscribe(const NacosString &serviceName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Unsubscribe event listener of service\r\n     *\r\n     * @param serviceName name of service\r\n     * @param groupName   group of service\r\n     * @param clusters    list of cluster\r\n     * @param listener    event listener\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual void unsubscribe(const NacosString &serviceName, const NacosString &groupName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Get all service names from server\r\n     *\r\n     * @param pageNo   page index\r\n     * @param pageSize page size\r\n     * @return list of service names\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual ListView<NacosString> getServiceList(int pageNo, int pageSize) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Get all service names from server\r\n     *\r\n     * @param pageNo    page index\r\n     * @param pageSize  page size\r\n     * @param groupName group name\r\n     * @return list of service names\r\n     * @throw (NacosException) = 0\r\n     */\r\n    virtual ListView<NacosString> getServiceList(int pageNo, int pageSize, const NacosString &groupName) NACOS_THROW (NacosException) = 0;\r\n\r\n    /**\r\n     * Get all service names from server with selector\r\n     *\r\n     * @param pageNo   page index\r\n     * @param pageSize page size\r\n     * @param selector selector to filter the resource\r\n     * @return list of service names\r\n     * @throw (NacosException) = 0\r\n     * @since 0.7.0\r\n     */\r\n    //virtual ListView<NacosString> getServicesOfServer(int pageNo, int pageSize, AbstractSelector selector) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get all service names from server with selector\r\n     *\r\n     * @param pageNo    page index\r\n     * @param pageSize  page size\r\n     * @param groupName group name\r\n     * @param selector  selector to filter the resource\r\n     * @return list of service names\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual ListView<NacosString> getServicesOfServer(int pageNo, int pageSize, const NacosString &groupName, AbstractSelector selector) throw (NacosException) = 0;\r\n\r\n    /**\r\n     * Get all subscribed services of current client\r\n     *\r\n     * @return subscribed services\r\n     * @throw (NacosException) = 0\r\n     */\r\n    //virtual std::list<ServiceInfo> getSubscribeServices() throw (NacosException) = 0;\r\n\r\n    /**\r\n     * get server health status\r\n     *\r\n     * @return is server healthy\r\n     */\r\n    //virtual NacosString getServerStatus() = 0;\r\n\r\n    virtual ~NamingService() {};\r\n};\r\n}//namespace nacos\r\n\r\n#endif"
  },
  {
    "path": "include/naming/ServiceInfo.h",
    "content": "#ifndef __SVC_INFO_H_\r\n#define __SVC_INFO_H_\r\n\r\n#include <list>\r\n#include \"NacosString.h\"\r\n#include \"naming/Instance.h\"\r\n\r\nnamespace nacos{\r\nclass ServiceInfo {\r\nprivate:\r\n    //@JSONField(serialize = false)\r\n    NacosString _jsonFromServer;\r\n\r\n    NacosString _name;\r\n\r\n    NacosString _groupName;\r\n\r\n    NacosString _clusters;\r\n\r\n    long _cacheMillis;\r\n\r\n    //@JSONField(name = \"hosts\")\r\n    std::list <Instance> _hosts;\r\n\r\n    long _lastRefTime;\r\n\r\n    NacosString _checksum;\r\n\r\n    volatile bool _allIPs;\r\n\r\npublic:\r\n    ServiceInfo();\r\n\r\n    bool isAllIPs() const;\r\n\r\n    void setAllIPs(bool allIPs);\r\n\r\n    explicit ServiceInfo(const NacosString &key);\r\n\r\n    ServiceInfo(const NacosString &name, const NacosString &clusters);\r\n\r\n    int ipCount();\r\n\r\n    bool expired() const;\r\n\r\n    void setHosts(std::list <Instance> &hosts);\r\n\r\n    bool isValid();\r\n\r\n    NacosString getName();\r\n\r\n    void setName(const NacosString &name);\r\n\r\n    NacosString getGroupName();\r\n\r\n    void setGroupName(const NacosString &groupName);\r\n\r\n    void setLastRefTime(long lastRefTime);\r\n\r\n    long getLastRefTime();\r\n\r\n    NacosString getClusters();\r\n\r\n    void setClusters(const NacosString &clusters);\r\n\r\n    long getCacheMillis();\r\n\r\n    void setCacheMillis(long cacheMillis);\r\n\r\n    std::list <Instance> getHosts();\r\n\r\n    std::list <Instance> *getHostsNocopy();\r\n\r\n    bool validate() const;\r\n\r\n    //@JSONField(serialize = false)\r\n    NacosString getJsonFromServer() const;\r\n\r\n    void setJsonFromServer(const NacosString &jsonFromServer);\r\n\r\n    //@JSONField(serialize = false)\r\n    NacosString getKey() const;\r\n\r\n    //@JSONField(serialize = false)\r\n    NacosString getKeyEncoded() const;\r\n\r\n    //@JSONField(serialize = false)\r\n    static void fromKey(ServiceInfo &serviceInfo, const NacosString &key);\r\n\r\n    //@JSONField(serialize = false)\r\n    static NacosString getKey(const NacosString &name, const NacosString &clusters);\r\n\r\n    //@Override\r\n    NacosString toString() const;\r\n\r\n    //!!BE CAREFUL!!\r\n    //This function is very expensive!! call it with care!\r\n    NacosString toInstanceString() const;\r\n\r\n    NacosString getChecksum() const;\r\n\r\n    void setChecksum(const NacosString &checksum);\r\n};\r\n}//namespace nacos\r\n\r\n#endif"
  },
  {
    "path": "include/naming/ServiceInfo2.h",
    "content": "#ifndef __SVC_INFO_2_H_\n#define __SVC_INFO_2_H_\n\n#include <list>\n#include \"NacosString.h\"\n#include \"naming/Cluster.h\"\n\nnamespace nacos{ namespace naming {\n\nclass Selector {\nprivate:\n    NacosString type;\npublic:\n\n    NacosString getType() const { return type; };\n\n    void setType(const NacosString &_type) { type = _type; };\n\n    virtual NacosString getSelectorString() = 0;\n};\n} /*naming*/\n\n//Actually this should be exactly the same as ServiceInfo but I designed this for compatibility\n//If you check the API reference in detail you'll find that:\n//the ServiceInfo returned by /nacos/v1/ns/service differs from the one returned by /nacos/v1/ns/instance/list\n//for more details, please refer :\n//https://nacos.io/zh-cn/docs/open-api.html#2.4  (Query instances)\n//https://nacos.io/zh-cn/docs/open-api.html#2.11 (Query service list)\nclass ServiceInfo2 {\nprivate:\n    bool nullObj;\n\n    bool namespaceIdIsSet;\n    NacosString namespaceId;\n\n    bool groupNameIsSet;\n    NacosString groupName;\n\n    bool nameIsSet;\n    NacosString name;\n\n    bool selectorIsSet;\n    NacosString selector;\n\n    bool protectThresholdIsSet;\n    double protectThreshold;\n\n    bool clustersIsSet;\n    std::list<Cluster> clusters;\n\n    bool metadataIsSet;\n    std::map<NacosString, NacosString> metadata;\npublic:\n    static ServiceInfo2 nullServiceInfo2;\n    ServiceInfo2() {\n        nullObj = true;\n        namespaceIdIsSet = false;\n        groupNameIsSet = false;\n        nameIsSet = false;\n        selectorIsSet = false;\n        protectThresholdIsSet = false;\n        clustersIsSet = false;\n        metadataIsSet = false;\n    }\n\n    void setNull(bool _isNull) { nullObj = _isNull; };\n    bool isNullObject() const { return nullObj; };\n\n    const NacosString &getNamespaceId() const {\n        return namespaceId;\n    }\n\n    void setNamespaceId(const NacosString &namespaceId) {\n        namespaceIdIsSet = true;\n        ServiceInfo2::namespaceId = namespaceId;\n    }\n\n    const NacosString &getGroupName() const {\n        return groupName;\n    }\n\n    void setGroupName(const NacosString &groupName) {\n        groupNameIsSet = true;\n        ServiceInfo2::groupName = groupName;\n    }\n\n    const NacosString &getName() const {\n        return name;\n    }\n\n    void setName(const NacosString &name) {\n        nameIsSet = true;\n        ServiceInfo2::name = name;\n    }\n\n    const NacosString &getSelector() const {\n        return selector;\n    }\n\n    void setSelector(const NacosString &aSelector) {\n        selectorIsSet = true;\n        selector = aSelector;\n    }\n\n    int getProtectThreshold() const {\n        return protectThreshold;\n    }\n\n    void setProtectThreshold(double protectThreshold) {\n        protectThresholdIsSet = true;\n        ServiceInfo2::protectThreshold = protectThreshold;\n    }\n\n    const std::list<Cluster> &getClusters() const {\n        return clusters;\n    }\n\n    void setClusters(const std::list<Cluster> &clusters) {\n        clustersIsSet = true;\n        ServiceInfo2::clusters = clusters;\n    }\n\n    const std::map<std::string, std::string> &getMetadata() const {\n        return metadata;\n    }\n\n    void setMetadata(const std::map<std::string, std::string> &metadata) {\n        metadataIsSet = true;\n        ServiceInfo2::metadata = metadata;\n    }\n\n    bool isNamespaceIdSet() const {\n        return namespaceIdIsSet;\n    }\n\n    bool isGroupNameSet() const {\n        return groupNameIsSet;\n    }\n\n    bool isNameSet() const {\n        return nameIsSet;\n    }\n\n    bool isSelectorSet() const {\n        return selectorIsSet;\n    }\n\n    bool isProtectThresholdSet() const {\n        return protectThresholdIsSet;\n    }\n\n    bool isClustersSet() const {\n        return clustersIsSet;\n    }\n\n    bool isMetadataSet() const {\n        return metadataIsSet;\n    }\n};\n}/*namespace nacos*/\n\n#endif"
  },
  {
    "path": "include/naming/selectors/HealthInstanceSelector.h",
    "content": "#ifndef __HEALTH_INST_SELECTOR_H_\n#define __HEALTH_INST_SELECTOR_H_\n\n#include <list>\n#include \"naming/selectors/Selector.h\"\n\nnamespace nacos { namespace naming { namespace selectors {\n\nclass HealthInstanceSelector : public Selector<Instance>{\nprivate:\npublic:\n    std::list<Instance> select(const std::list<Instance> &instancesToSelect);\n};\n} /*selectors*/ } /*naming*/ }/*nacos*/\n\n#endif"
  },
  {
    "path": "include/naming/selectors/RandomByWeightSelector.h",
    "content": "#ifndef __WEIGHTED_RND_SELECTOR_H_\n#define __WEIGHTED_RND_SELECTOR_H_\n\n#include <list>\n#include \"naming/selectors/Selector.h\"\n\n#define BASIC_WEIGHT 65536\n\nnamespace nacos { namespace naming { namespace selectors {\nclass RandomByWeightSelector : public Selector<Instance>{\nprivate:\npublic:\n    std::list<Instance> select(const std::list<Instance> &instancesToSelect);\n};\n} /*selectors*/ } /*naming*/ }/*nacos*/\n\n#endif"
  },
  {
    "path": "include/naming/selectors/RandomSelector.h",
    "content": "#ifndef __RND_SELECTOR_H_\n#define __RND_SELECTOR_H_\n\n#include <list>\n#include \"naming/selectors/Selector.h\"\n\nnamespace nacos { namespace naming { namespace selectors {\nclass RandomSelector : public Selector<Instance>{\nprivate:\npublic:\n    std::list<Instance> select(const std::list<Instance> &instancesToSelect);\n};\n} /*selectors*/ } /*naming*/ }/*nacos*/\n\n#endif"
  },
  {
    "path": "include/naming/selectors/Selector.h",
    "content": "#ifndef __SELECTOR_H_\n#define __SELECTOR_H_\n\n#include <list>\n#include \"naming/Instance.h\"\n\nnamespace nacos { namespace naming { namespace selectors {\n//Selector interface definition\n//All Selectors shall be THREAD-SAFE!\n\ntemplate<typename T>\nclass Selector {\nprivate:\npublic:\n    virtual std::list<T> select(const std::list<T> &itemsToSelect) = 0;\n\n    virtual ~Selector() {};\n};\n\n} /*selectors*/ } /*naming*/ }/*nacos*/\n\n#endif"
  },
  {
    "path": "include/naming/subscribe/EventListener.h",
    "content": "//\n// Created by liuhanyu on 2020/9/24.\n//\n\n#ifndef NACOS_SDK_CPP_EVENTLISTENER_H\n#define NACOS_SDK_CPP_EVENTLISTENER_H\n\n#include \"NacosString.h\"\n#include \"thread/AtomicInt.h\"\n#include \"naming/ChangeAdvice.h\"\n\nnamespace nacos{\nclass EventListener {\nprivate:\n    NacosString listenerName;\n    AtomicInt<int> refCount;\npublic:\n    EventListener() {\n        this->listenerName = \"theListener\";\n    };\n\n    int incRef() { return refCount.inc(); };\n\n    int decRef() { return refCount.dec(); };\n\n    int refCnt() const { return refCount.get(); };\n\n    void setListenerName(const NacosString &name) { this->listenerName = name; };\n\n    NacosString getListenerName() const { return listenerName; };\n\n    virtual void receiveNamingInfo(const ServiceInfo &changeAdvice) = 0;\n\n    virtual ~EventListener();\n};\n}//namespace nacos\n\n\n#endif //NACOS_SDK_CPP_EVENTLISTENER_H\n"
  },
  {
    "path": "include/server/ServerSelector.h",
    "content": "#ifndef NACOS_SDK_CPP_SERVERSELECTOR_H\n#define NACOS_SDK_CPP_SERVERSELECTOR_H\n\n#include \"NacosServerInfo.h\"\n#include <list>\n\n/*\n* ServerSelector\n* Author: Liu, Hanyu\n* Selector interface, to select one server from the select list\n* User can implement different selecting strategies (e.g.: Weighed, Random, Least used) by implementing select() method\n*/\nnamespace nacos{\nclass ServerSelector {\npublic:\n    virtual NacosServerInfo select(std::list <NacosServerInfo> &serverList) = 0;\n\n    virtual ~ServerSelector() {};\n};\n}//namespace nacos\n\n#endif //NACOS_SDK_CPP_SERVERSELECTOR_H\n"
  },
  {
    "path": "include/thread/AtomicInt.h",
    "content": "#ifndef __ATOMIC_INT_H_\n#define __ATOMIC_INT_H_\n\nnamespace nacos{\ntemplate<typename T>\nclass AtomicInt {\nprivate:\n    volatile T _curval;\npublic:\n    AtomicInt(T curval = 0) : _curval(curval) {};\n\n    void set(T val) { _curval = val; };\n\n    T inc(T incval = 1) {\n        T oldValue = getAndInc(incval);\n        return incval + oldValue;\n    };\n\n    T getAndInc(T incval = 1) {\n        T oldValue = __sync_fetch_and_add(&_curval, incval);\n        return oldValue;\n    }\n\n    T dec(int decval = 1) {\n        return inc(-decval);\n    };\n\n    T get() const { return _curval; };\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "nacos-cpp-cli.properties",
    "content": "#!!please NOTE that the file format for this properties should be UNIX!!\n#specify nacos server address here(separated by ,)\n#serverAddr=\n\n#log path, default is ~/nacos/logs/\n#nacos.log.path=\n\n#rotate size (number [+ unit], unit can be k/K m/M g/G. the size is regarded as byte if there is no unit)\n#nacos.log.rotateSize=100m\n\n#log level, default is ERROR\n#nacos.log.level=ERROR\n\n#client IP, the client will automatically detect NIC and find the best IP\n#but if that doesn't work, you can override it here manually\n#nacos.client.ip=\n\n#if the server is secured with password, you may specify it here\n#nacos.auth.username=\n#nacos.auth.password=\n\n#specify this if you are using an endpoint\n#endpoint=\n#endpointPort=\n\n#specify context path for nacos server (\"nacos\" by default)\n#nacos.server.contextpath=\n\n#advanced settings\n#port for udp listener (to receive service change information for subscribed services)\n#nacos.udp.port=\n\n#poller interval (10000 ms by default) to refresh subscribed service information from server\n#naming.poller.interval=\n\n#accessKey/secretKey for SPAS\n#accessKey=\n#secretKey=\n"
  },
  {
    "path": "src/NacosExceptions.cpp",
    "content": "#include \"NacosExceptions.h\"\r\n\r\nnamespace nacos{\r\nNacosException::NacosException(int errorcode, const char *errormsg) NACOS_NOTHROW() {\r\n    _errcode = errorcode;\r\n    _errmsg = errormsg;\r\n}\r\n\r\nNacosException::NacosException(int errorcode, const NacosString &errormsg) NACOS_NOTHROW() {\r\n    _errcode = errorcode;\r\n    _errmsg = errormsg;\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/NacosString.cpp",
    "content": "#include <math.h>\r\n#include <stdio.h>\r\n#include <sstream>\r\n#include \"NacosString.h\"\r\n\r\nnamespace nacos{\r\nconst NacosString NacosStringOps::nullstr = \"\";\r\nconst NacosString NacosStringOps::STR_TRUE = \"true\";\r\nconst NacosString NacosStringOps::STR_FALSE = \"false\";\r\n\r\n//Returns true if str refers to nullstr\r\nbool NacosStringOps::isNullStr(const NacosString &str) {\r\n    return (&str == &nullstr) || (str == \"\");\r\n}\r\n\r\ntemplate<>\r\nNacosString NacosStringOps::valueOf<bool>(bool val) {\r\n    if (val) { return STR_TRUE; }\r\n    else { return STR_FALSE; }\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/config/AppConfigManager.cpp",
    "content": "#include \"src/utils/ParamUtils.h\"\n#include \"AppConfigManager.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"src/utils/NetUtils.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"NacosExceptions.h\"\n#include \"src/utils/DirUtils.h\"\n#include <vector>\n#include <stdlib.h>\n#include \"src/log/Logger.h\"\n#include \"src/utils/ConfigParserUtils.h\"\n#include \"src/utils/Env.h\"\n\nusing namespace std;\n\nnamespace nacos{\n\nbool AppConfigManager::nacosAuthEnabled() {\n    if (contains(PropertyKeyConst::AUTH_USERNAME) && contains(PropertyKeyConst::AUTH_PASSWORD)) {\n        return true;\n    } else {\n        return false;\n    }\n}\n\nvoid AppConfigManager::checkReloadable() NACOS_THROW(NacosException) {\n    if (!reloadable) {\n        throw NacosException(0, \"This object is initialized as a non-reloadable one\");\n    }\n}\n\nsize_t AppConfigManager::loadConfig() NACOS_THROW(NacosException) {\n    checkReloadable();\n    initDefaults();\n    Properties parsedConfig = ConfigParserUtils::parseConfigFile(configFile);\n    applyConfig(parsedConfig);\n    log_debug(\"[AppConfigManager]-loadConfig:loaded config file:%s\\n\", appConfig.toString().c_str());\n    return appConfig.size();\n}\n\nsize_t AppConfigManager::loadConfig(const NacosString &_configFile) NACOS_THROW(NacosException) {\n    checkReloadable();\n    configFile = _configFile;\n    loadConfig();\n    return appConfig.size();\n}\n\nvoid AppConfigManager::clearConfig() {\n    appConfig.clear();\n}\n\nconst NacosString& AppConfigManager::get(const NacosString &key) {\n    if (appConfig.count(key) == 0) {\n        return NULLSTR;\n    }\n\n    if (key.compare(PropertyKeyConst::NAMESPACE) == 0\n        && appConfig[PropertyKeyConst::NAMESPACE].compare(\"Public\") == 0)\n    {\n        return NULLSTR;\n    }\n\n    Properties::iterator iter = appConfig.find(key);\n    if (iter == appConfig.end()) {\n        return NULLSTR;\n    }\n    \n    return iter->second;\n}\n\nvoid AppConfigManager::set(const NacosString &key, const NacosString &value) {\n    //Special case handle\n    if (key.compare(PropertyKeyConst::SERVER_REQ_TIMEOUT) == 0) {\n        _serverReqTimeout = atoi(value.c_str());\n    } else if (key.compare(PropertyKeyConst::CONTEXT_PATH) == 0) {\n        _contextPath = value;\n    }\n    appConfig[key] = value;\n}\n\nbool AppConfigManager::contains(const std::string &key) const {\n    return appConfig.contains(key);\n}\n\nAppConfigManager::AppConfigManager(Properties &props) {\n    reloadable = false;\n    initDefaults();\n    applyConfig(props);\n}\n\nAppConfigManager::AppConfigManager(const NacosString &_configFile) {\n    reloadable = true;\n    configFile = _configFile;\n}\n\nNacosString getAppNameFromEnv() {\n    const char* env = getEnv(\"APP_NAME\");\n    if (env != NULL && std::char_traits<char>::length(env) > 0) {\n        return NacosString(env);\n    }\n\n    return NacosStringOps::nullstr;\n}\n\nvoid AppConfigManager::initDefaults() {\n    appConfig.clear();\n    //appConfig[PropertyKeyConst::NAMESPACE] = \"public\";\n    set(PropertyKeyConst::SRVLISTMGR_REFRESH_INTERVAL, \"30000\");\n    set(PropertyKeyConst::SERVER_REQ_TIMEOUT, \"3000\");\n    set(PropertyKeyConst::CONTEXT_PATH, ConfigConstant::DEFAULT_CONTEXT_PATH);\n    set(PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL, \"10000\");//10 secs by default\n    set(PropertyKeyConst::CONFIG_LONGPULLLING_TIMEOUT, \"30000\");//ms\n    set(PropertyKeyConst::HB_FAIL_WAIT_TIME, \"20000\");//ms\n    set(PropertyKeyConst::CLIENT_NAME, \"default\");\n    set(PropertyKeyConst::LOCAL_IP, NetUtils::getHostIp());\n    set(PropertyKeyConst::UDP_RECEIVER_PORT, \"30620\");\n\n    NacosString appName = getAppNameFromEnv();\n    if (!NacosStringOps::isNullStr(appName)) {\n        set(PropertyKeyConst::APP_NAME, appName);\n    }\n    \n    NacosString homedir = DirUtils::getHome();\n\n    set(PropertyKeyConst::INSTANCE_ID_PREFIX, NetUtils::getHostName());\n    set(PropertyKeyConst::INSTANCE_ID_SEQ_FILE, homedir + ConfigConstant::FILE_SEPARATOR + \"nacos\" + ConfigConstant::FILE_SEPARATOR + \"instance_seq.dat\");\n    set(PropertyKeyConst::NACOS_SNAPSHOT_PATH, homedir + ConfigConstant::FILE_SEPARATOR + \"nacos\" + ConfigConstant::FILE_SEPARATOR + \"snapshot\");\n    log_info(\"[AppConfigManager]-initDefaults:DEFAULT_SNAPSHOT_PATH:%s\\n\", appConfig[PropertyKeyConst::NACOS_SNAPSHOT_PATH].c_str());\n}\n\nvoid AppConfigManager::applyConfig(Properties &rhs) {\n    for (map<NacosString, NacosString>::iterator it = rhs.begin();\n         it != rhs.end(); it++) {\n        set(it->first, it->second);\n    }\n}\n\n}//namespace nacos"
  },
  {
    "path": "src/config/AppConfigManager.h",
    "content": "#ifndef __APP_CFG_MGR_H_\n#define __APP_CFG_MGR_H_\n\n#include \"NacosExceptions.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\n\nclass AppConfigManager {\nprivate:\n    bool reloadable;\n    Properties appConfig;\n    NacosString configFile;\n    //Cached contextpath\n    NacosString _contextPath;\n\n    volatile long _serverReqTimeout;\n\n    AppConfigManager();\n\n    void checkReloadable() NACOS_THROW(NacosException);\n\n    void initDefaults();\n\n    void applyConfig(Properties &rhs);\n\npublic:\n    bool nacosAuthEnabled();\n\n    long getServeReqTimeout() const { return _serverReqTimeout; };\n\n    bool isReloadable() const { return reloadable; };\n\n    AppConfigManager(Properties &props);\n\n    AppConfigManager(const NacosString &configFile);\n\n    size_t loadConfig(const NacosString &configFile) NACOS_THROW(NacosException);\n\n    size_t loadConfig() NACOS_THROW(NacosException);\n\n    void clearConfig();\n\n    const NacosString &get(const NacosString &key);\n\n    bool contains(const NacosString &key) const;\n\n    const Properties& getAllConfig() { return appConfig; };\n\n    const NacosString & getContextPath() const { return _contextPath; };\n\n    void set(const NacosString &key, const NacosString &value);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/config/ConcurrentDiskUtil.cpp",
    "content": "#include <errno.h>\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\n#include <sys/file.h>\r\n#include \"ConcurrentDiskUtil.h\"\r\n#include \"IOUtils.h\"\r\n\r\n/**\r\n * get file content\r\n *\r\n * @param file        file\r\n * @param charsetName charsetName\r\n * @return content\r\n * @throws IOException IOException\r\n */\r\n\r\nnamespace nacos{\r\nNacosString\r\nConcurrentDiskUtil::getFileContent(const NacosString &file, const NacosString &charsetName) NACOS_THROW(IOException) {\r\n    if (IOUtils::checkNotExistOrNotFile(file)) {\r\n        //TODO:add errorcode\r\n        throw IOException(NacosException::FILE_NOT_FOUND,\r\n                          \"checkNotExistOrNotFile failed, unable to access the file, maybe it doesn't exist.\");\r\n    }\r\n    size_t toRead = IOUtils::getFileSize(file);\r\n    FILE *fp = fopen(file.c_str(), \"rb\");\r\n    if (fp == NULL) {\r\n        char errbuf[100];\r\n        snprintf(errbuf, sizeof(errbuf), \"Failed to open file for read, errno: %d\", errno);\r\n        //TODO:add errorcode\r\n        throw IOException(NacosException::UNABLE_TO_OPEN_FILE, errbuf);\r\n    }\r\n    flock(fileno(fp), LOCK_SH);\r\n    char buf[toRead + 1];\r\n    fread(buf, toRead, 1, fp);\r\n    buf[toRead] = '\\0';\r\n    flock(fileno(fp), LOCK_UN);\r\n    fclose(fp);\r\n    return NacosString(buf);\r\n}\r\n\r\n/**\r\n * write file content\r\n *\r\n * @param file        file\r\n * @param content     content\r\n * @param charsetName charsetName\r\n * @return whether write ok\r\n * @throws IOException IOException\r\n */\r\nbool ConcurrentDiskUtil::writeFileContent\r\n        (\r\n                const NacosString &path,\r\n                const NacosString &content,\r\n                const NacosString &charsetName\r\n        ) NACOS_THROW(IOException) {\r\n    FILE *fp = fopen(path.c_str(), \"wb\");\r\n    if (fp == NULL) {\r\n        char errbuf[100];\r\n        snprintf(errbuf, sizeof(errbuf), \"Failed to open file for write, errno: %d\", errno);\r\n        //TODO:add errorcode\r\n        throw IOException(NacosException::UNABLE_TO_OPEN_FILE, errbuf);\r\n    }\r\n    flock(fileno(fp), LOCK_SH);\r\n    fwrite(content.c_str(), content.size(), 1, fp);\r\n    flock(fileno(fp), LOCK_UN);\r\n    fclose(fp);\r\n    return true;\r\n}\r\n}//namespace nacos"
  },
  {
    "path": "src/config/ConcurrentDiskUtil.h",
    "content": "#ifndef __CONC_DISK_UTIL_H_\n#define __CONC_DISK_UTIL_H_\n\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass ConcurrentDiskUtil {\npublic:\n    /**\n     * get file content\n     *\n     * @param file        file\n     * @param charsetName charsetName\n     * @return content\n     * @throws IOException IOException\n     */\n    static NacosString getFileContent(const NacosString &file, const NacosString &charsetName) NACOS_THROW(IOException);\n\n    /**\n     * write file content\n     *\n     * @param file        file\n     * @param content     content\n     * @param charsetName charsetName\n     * @return whether write ok\n     * @throws IOException IOException\n     */\n    static bool writeFileContent(const NacosString &path, const NacosString &content,\n                                 const NacosString &charsetName) NACOS_THROW(IOException);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/config/ConfigProxy.cpp",
    "content": "//\n// Created by liuhanyu on 2021/7/6.\n//\n\n#include \"ConfigProxy.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"src/utils/TimeUtils.h\"\n#include \"src/config/AppConfigManager.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/crypto/SignatureTool.h\"\n\nnamespace nacos {\n\nNacosString ConfigProxy::getDataToSign(const std::list <NacosString> &paramValues, const NacosString &nowTimeMs) {\n    const NacosString & group = ParamUtils::findByKey(paramValues, \"group\");\n    const NacosString & tenant = ParamUtils::findByKey(paramValues, \"tenant\");\n    NacosString dataToSign = \"\";\n    if (!NacosStringOps::isNullStr(tenant)) {\n        dataToSign = tenant + \"+\";\n    }\n    if (!NacosStringOps::isNullStr(group)) {\n        dataToSign += group;\n    }\n\n    if (!NacosStringOps::isNullStr(dataToSign)) {\n        dataToSign += \"+\" + nowTimeMs;\n    } else {\n        dataToSign = nowTimeMs;\n    }\n\n    return dataToSign;\n}\n\nHttpResult ConfigProxy::reqAPI\n        (\n                int method,\n                const NacosString &path,\n                std::list <NacosString> &headers,\n                std::list <NacosString> &paramValues,\n                const NacosString &encoding,\n                long readTimeoutMs\n        ) NACOS_THROW(NetworkException) {\n    HttpDelegate *_httpDelegate = _objectConfigData->_httpDelegate;\n\n    //TODO: refactor to a common procedure\n    const NacosString& secretKey = _objectConfigData->_appConfigManager->get(PropertyKeyConst::SECRET_KEY);\n    const NacosString& accessKey = _objectConfigData->_appConfigManager->get(PropertyKeyConst::ACCESS_KEY);\n    const NacosString& appName = _objectConfigData->_appConfigManager->get(PropertyKeyConst::APP_NAME);\n\n    //If SPAS security credentials are set, SPAS is enabled\n    if (!ParamUtils::isBlank(secretKey) && !ParamUtils::isBlank(accessKey)) {\n        NacosString nowTimeMs = NacosStringOps::valueOf(TimeUtils::getCurrentTimeInMs());\n        NacosString dataToSign = getDataToSign(paramValues, nowTimeMs);\n        NacosString signature = SignatureTool::SignWithHMAC_SHA1(dataToSign, secretKey);\n        ParamUtils::addKV(headers, \"Spas-Signature\", signature);\n        ParamUtils::addKV(headers, \"Timestamp\", nowTimeMs);\n        ParamUtils::addKV(headers, \"Spas-AccessKey\", accessKey);\n    }\n\n\n    if (!NacosStringOps::isNullStr(appName)) {\n        ParamUtils::addKV(headers, \"Client-AppName\", appName);\n    }\n\n    switch (method) {\n        case IHttpCli::GET:\n            return _httpDelegate->httpGet(path, headers, paramValues, encoding, readTimeoutMs);\n        case IHttpCli::POST:\n            return _httpDelegate->httpPost(path, headers, paramValues, encoding, readTimeoutMs);\n        case IHttpCli::PUT:\n            return _httpDelegate->httpPut(path, headers, paramValues, encoding, readTimeoutMs);\n        case IHttpCli::DELETE:\n            return _httpDelegate->httpDelete(path, headers, paramValues, encoding, readTimeoutMs);\n        default://should never happen\n            abort();\n    }\n}\n}"
  },
  {
    "path": "src/config/ConfigProxy.h",
    "content": "//\n// Created by liuhanyu on 2021/7/6.\n//\n\n#ifndef NACOS_SDK_CPP_CONFIGPROXY_H\n#define NACOS_SDK_CPP_CONFIGPROXY_H\n#include \"src/factory/ObjectConfigData.h\"\n#include \"src/http/IHttpCli.h\"\n\nnamespace nacos {\n\nclass ConfigProxy {\nprivate:\n    ObjectConfigData *_objectConfigData;\n    NacosString getDataToSign(const std::list <NacosString> &paramValues, const NacosString &nowTimeMs);\npublic:\n    ConfigProxy(ObjectConfigData *objectConfigData) : _objectConfigData(objectConfigData) {};\n    HttpResult reqAPI(int method, const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                         const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n};\n\n}\n\n#endif //NACOS_SDK_CPP_CONFIGPROXY_H\n"
  },
  {
    "path": "src/config/IOUtils.cpp",
    "content": "#include \"IOUtils.h\"\r\n#include <sys/stat.h>\r\n#include <sys/types.h>\r\n#include <dirent.h>\r\n#include <string.h>\r\n#include <errno.h>\r\n#include <stdio.h>\r\n#include <limits.h>\r\n#include <list>\r\n#include <unistd.h>\r\n#include \"src/log/Logger.h\"\r\n\r\nnamespace nacos{\r\nsize_t IOUtils::getFileSize(const NacosString &file) {\r\n    struct stat statbuf;\r\n\r\n    if (stat(file.c_str(), &statbuf) == -1) {\r\n        return 0;\r\n    }\r\n\r\n    return statbuf.st_size;\r\n}\r\n\r\nNacosString IOUtils::readStringFromFile(const NacosString &file, const NacosString &encoding) NACOS_THROW(IOException) {\r\n    size_t toRead = getFileSize(file);\r\n    FILE *fp = fopen(file.c_str(), \"rb\");\r\n    if (fp == NULL) {\r\n        throw IOException(NacosException::FILE_NOT_FOUND, \"File not found:\" + file);\r\n    }\r\n    char buf[toRead + 1];\r\n    fread(buf, toRead, 1, fp);\r\n    buf[toRead] = '\\0';\r\n    fclose(fp);\r\n    return NacosString(buf);\r\n}\r\n\r\nvoid IOUtils::writeStringToFile(const NacosString &file, const NacosString &data,\r\n                                const NacosString &encoding) NACOS_THROW(IOException) {\r\n    FILE *fp = fopen(file.c_str(), \"wb\");\r\n    fwrite(data.c_str(), data.size(), 1, fp);\r\n    fclose(fp);\r\n}\r\n\r\n//Returns true if:\r\n//a. the file doesn't exist\r\n//b. the file is not a regular file\r\nbool IOUtils::checkNotExistOrNotFile(const NacosString &pathname) {\r\n    struct stat thestat = {0};\r\n    int res = stat(pathname.c_str(), &thestat);\r\n\r\n    if (res != 0) {\r\n        if (errno == ENOENT) {\r\n            //a. the file doesn't exist\r\n            return true;\r\n        } else {\r\n            //Maybe something's wrong with the permission\r\n            //Anyway, we have no access to this file\r\n            return true;\r\n        }\r\n    }\r\n\r\n    if (!S_ISREG(thestat.st_mode)) {\r\n        //b. the file is not a regular file\r\n        return true;\r\n    } else {\r\n\r\n        //This IS a regular file\r\n        return false;\r\n    }\r\n}\r\n\r\n//Returns true if:\r\n//a. the file doesn't exist\r\n//b. the file is not a directory\r\nbool IOUtils::checkNotExistOrNotDir(const NacosString &pathname) {\r\n    struct stat thestat = {0};\r\n    int res = stat(pathname.c_str(), &thestat);\r\n\r\n    if (res != 0) {\r\n        if (errno == ENOENT) {\r\n            //a. the file doesn't exist\r\n            return true;\r\n        } else {\r\n            //Maybe something's wrong with the permission\r\n            //Anyway, we have no access to this file\r\n            return true;\r\n        }\r\n    }\r\n\r\n    if (!S_ISDIR(thestat.st_mode)) {\r\n        //b. the file is not a directory\r\n        return true;\r\n    } else {\r\n        //This IS a directory\r\n        return false;\r\n    }\r\n}\r\n\r\n//TODO:To provide compability across different platforms\r\nNacosString IOUtils::getParentFile(const NacosString &thefile) {\r\n    size_t parentFilePos = thefile.rfind('/');\r\n    //Invalid Directory/Filename, returning empty\r\n    if (parentFilePos == std::string::npos || parentFilePos == 0) {\r\n        return NULLSTR;\r\n    }\r\n    NacosString parentFile = thefile.substr(0, parentFilePos);\r\n    return parentFile;\r\n}\r\n\r\n//Upon success, return true\r\n//Upon failure, return false\r\nbool IOUtils::recursivelyRemove(const NacosString &file) {\r\n    struct stat thestat;\r\n\r\n    if (stat(file.c_str(), &thestat) == -1 && errno != ENOENT) {\r\n        //Something's wrong, and it's not \"FileNotExist\", we should record this and exit\r\n        log_error(\"Failed to stat() file, errno: %d\\n\", errno);\r\n        return false;\r\n    }\r\n\r\n    if (S_ISDIR(thestat.st_mode)) {\r\n        DIR *curdir = opendir(file.c_str());\r\n        struct dirent *direntp = readdir(curdir);\r\n        while (direntp != NULL) {\r\n            if (!strcmp(direntp->d_name, \".\") || !strcmp(direntp->d_name, \"..\")) {\r\n                //skip this dir and parent\r\n                direntp = readdir(curdir);\r\n                continue;\r\n            }\r\n            struct stat subfilestat;\r\n            NacosString subfilepath = file + \"/\" + direntp->d_name;\r\n\r\n            if (stat(subfilepath.c_str(), &subfilestat) == -1 && errno != ENOENT) {\r\n                log_error(\"Failed to stat() file, errno: %d\\n\", errno);\r\n                closedir(curdir);\r\n                return false;\r\n            }\r\n            if (S_ISREG(subfilestat.st_mode)) {\r\n                remove(subfilepath.c_str());\r\n            } else if (S_ISDIR(subfilestat.st_mode)) {\r\n                recursivelyRemove(subfilepath);\r\n            }\r\n            //get to the next entry\r\n            direntp = readdir(curdir);\r\n        }\r\n        closedir(curdir);\r\n        remove(file.c_str());\r\n    } else if (S_ISREG(thestat.st_mode)) {\r\n        remove(file.c_str());\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\nbool IOUtils::cleanDirectory(const NacosString &file) {\r\n    struct stat thestat;\r\n\r\n    if (stat(file.c_str(), &thestat) == -1 && errno != ENOENT) {\r\n        //Something's wrong, and it's not \"FileNotExist\", we should record this and exit\r\n        log_error(\"Failed to stat() file, errno: %d\\n\", errno);\r\n        return false;\r\n    }\r\n\r\n    if (!S_ISDIR(thestat.st_mode)) {\r\n        log_error(\"Call cleanDirectory() on non-directory entity: %s\\n\", file.c_str());\r\n        return false;\r\n    }\r\n\r\n    DIR *curdir = opendir(file.c_str());\r\n    struct dirent *direntp = readdir(curdir);\r\n    while (direntp != NULL) {\r\n        if (!strcmp(direntp->d_name, \".\") || !strcmp(direntp->d_name, \"..\")) {\r\n            //skip this dir and parent\r\n            direntp = readdir(curdir);\r\n            continue;\r\n        }\r\n        NacosString subfilepath = file + \"/\" + direntp->d_name;\r\n\r\n        recursivelyRemove(subfilepath);\r\n        //get to the next entry\r\n        direntp = readdir(curdir);\r\n    }\r\n    closedir(curdir);\r\n\r\n    return true;\r\n}\r\n\r\nvoid IOUtils::recursivelyCreate(const NacosString &file) {\r\n    NacosString parentFile = getParentFile(file);\r\n    if (!isNull(parentFile)) {\r\n        recursivelyCreate(parentFile);\r\n    }\r\n\r\n    if (checkNotExistOrNotDir(file)) {\r\n        mkdir(file.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);\r\n    }\r\n}\r\n\r\nstd::list <NacosString> IOUtils::listFiles(const NacosString &path) {\r\n    struct stat thestat;\r\n    std::list <NacosString> filelist;\r\n    if (stat(path.c_str(), &thestat) == -1 && errno != ENOENT) {\r\n        //Something's wrong, and it's not \"FileNotExist\", we should record this and exit\r\n        log_error(\"Failed to stat() file, errno: %d\\n\", errno);\r\n        return filelist;\r\n    }\r\n\r\n    if (!S_ISDIR(thestat.st_mode)) {\r\n        log_error(\"Call listFiles() on non-directory entity: %s\\n\", path.c_str());\r\n        return filelist;\r\n    }\r\n\r\n    DIR *curdir = opendir(path.c_str());\r\n    struct dirent *direntp = readdir(curdir);\r\n    while (direntp != NULL) {\r\n        if (!strcmp(direntp->d_name, \".\") || !strcmp(direntp->d_name, \"..\")) {\r\n            //skip this dir and parent\r\n            direntp = readdir(curdir);\r\n            continue;\r\n        }\r\n        NacosString curitem = direntp->d_name;\r\n        filelist.push_back(curitem);\r\n        //get to the next entry\r\n        direntp = readdir(curdir);\r\n    }\r\n    closedir(curdir);\r\n\r\n    return filelist;\r\n}\r\n}//namespace nacos"
  },
  {
    "path": "src/config/IOUtils.h",
    "content": "#ifndef __IO_UTILS_H_\n#define __IO_UTILS_H_\n\n#include <list>\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass IOUtils {\nprivate:\npublic:\n    static size_t getFileSize(const NacosString &file);\n\n    static NacosString readStringFromFile(const NacosString &file, const NacosString &encoding) NACOS_THROW(IOException);\n\n    static void\n    writeStringToFile(const NacosString &file, const NacosString &data, const NacosString &encoding) NACOS_THROW(IOException);\n\n    //Returns true if:\n    //a. the file doesn't exist\n    //b. the file is not a regular file\n    static bool checkNotExistOrNotFile(const NacosString &pathname);\n\n    //Returns true if:\n    //a. the file doesn't exist\n    //b. the file is not a directory\n    static bool checkNotExistOrNotDir(const NacosString &pathname);\n\n    //TODO:To provide compability across different platforms\n    static NacosString getParentFile(const NacosString &thefile);\n\n    //Upon success, return true\n    //Upon failure, return false\n    static bool recursivelyRemove(const NacosString &file);\n\n    static bool cleanDirectory(const NacosString &file);\n\n    static void recursivelyCreate(const NacosString &file);\n\n    static std::list <NacosString> listFiles(const NacosString &path);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/config/JVMUtil.h",
    "content": "#ifndef __JVMUTIL_H_\n#define __JVMUTIL_H_\n\nnamespace nacos{\nclass JVMUtil {\npublic:\n    /**\n     * whether is multi instance\n     *\n     * @return whether multi\n     */\n    static bool isMultiInstance() {\n        return _isMultiInstance;\n    };\nprivate:\n    static bool _isMultiInstance;\n\n    /*static {\n        NacosString multiDeploy = System.getProperty(\"isMultiInstance\", \"false\");\n        if (TRUE.equals(multiDeploy)) {\n            isMultiInstance = true;\n        }\n        LOGGER.info(\"isMultiInstance:{}\", isMultiInstance);\n    }*/\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/config/LocalSnapshotManager.cpp",
    "content": "#include \"LocalSnapshotManager.h\"\n#include <stdio.h>\n#include <list>\n#include <unistd.h>\n#include <sys/types.h>\n#include <errno.h>\n#include \"NacosExceptions.h\"\n#include \"NacosString.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"src/utils/DirUtils.h\"\n#include \"SnapShotSwitch.h\"\n#include \"JVMUtil.h\"\n#include \"ConcurrentDiskUtil.h\"\n#include \"IOUtils.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/log/Logger.h\"\n\nnamespace nacos{\n\nNacosString LocalSnapshotManager::getFailover(const NacosString &serverName, const NacosString &dataId,\n                                                  const NacosString &group, const NacosString &tenant) {\n    NacosString localPath = getFailoverFile(serverName, dataId, group, tenant);\n\n    if (IOUtils::checkNotExistOrNotFile(localPath)) {\n        log_debug(\"[LocalSnapshotManager]-getFailover:[servername=%s] failover file %s doesn't exist\\n\",\n                  serverName.c_str(), localPath.c_str());\n        return NULLSTR;\n    }\n\n    try {\n        return readFile(localPath);\n    } catch (IOException &ioe) {\n        log_error(\"[LocalSnapshotManager]-getFailover:[servername=%s] get failover error, file: %s, exception:%s\\n\", serverName.c_str(), localPath.c_str(), ioe.what());\n        return NULLSTR;\n    }\n};\n\n/**\n * 获取本地缓存文件内容。NULL表示没有本地文件或抛出异常。\n */\nNacosString LocalSnapshotManager::getSnapshot\n        (\n                const NacosString &name,\n                const NacosString &dataId,\n                const NacosString &group,\n                const NacosString &tenant\n        ) {\n    if (!SnapShotSwitch::getIsSnapShot()) {\n        return NULLSTR;\n    }\n    NacosString file = getSnapshotFile(name, dataId, group, tenant);\n    if (IOUtils::checkNotExistOrNotFile(file)) {\n        return NULLSTR;\n    }\n\n    try {\n        return readFile(file);\n    } catch (IOException &ioe) {\n        log_error(\"[LocalSnapshotManager]-getSnapshot:[servername=%s]+get snapshot error, file:%s what:%s\\n\", name.c_str(), file.c_str(), ioe.what());\n        return NULLSTR;\n    }\n};\n\nNacosString LocalSnapshotManager::readFile(const NacosString &file) NACOS_THROW(IOException) {\n    if (IOUtils::checkNotExistOrNotFile(file)) {\n        return NULLSTR;\n    }\n\n    if (JVMUtil::isMultiInstance()) {\n        return ConcurrentDiskUtil::getFileContent(file, ConfigConstant::ENCODE);\n    } else {\n        return IOUtils::readStringFromFile(file, ConfigConstant::ENCODE);\n    }\n};\n\nvoid\nLocalSnapshotManager::saveSnapshot(const NacosString &envName, const NacosString &dataId, const NacosString &group,\n                                       const NacosString &tenant, const NacosString &config) {\n    if (!SnapShotSwitch::getIsSnapShot()) {\n        return;\n    }\n\n    NacosString file = getSnapshotFile(envName, dataId, group, tenant);\n    if (isNull(config)) {\n        int remove_result = remove(file.c_str());\n        if (remove_result)//error happens when removing the file\n        {\n            //usually we get this error because we are deleting a non-existent file\n            log_debug(\"[LocalSnapshotManager]-saveSnapshot:[servername=%s] delete snapshot error, remove() returns %d, errno = %d\\n\",\n                      envName.c_str(), remove_result, errno);\n        }\n    } else {\n        NacosString parentFile = IOUtils::getParentFile(file);\n        if (IOUtils::checkNotExistOrNotDir(parentFile)) {\n            IOUtils::recursivelyCreate(parentFile);\n            //LOGGER.error(\"[{}] save snapshot error\", envName);\n        }\n\n        if (JVMUtil::isMultiInstance()) {\n            ConcurrentDiskUtil::writeFileContent(file, config, ConfigConstant::ENCODE);\n        } else {\n            IOUtils::writeStringToFile(file, config, ConfigConstant::ENCODE);\n        }\n\n        //LOGGER.error(\"[\" + envName + \"] save snapshot error, \" + file, ioe);\n    }\n};\n\n/**\n * 清除snapshot目录下所有缓存文件。\n */\nvoid LocalSnapshotManager::cleanAllSnapshot() {\n    std::list <NacosString> rootFile = IOUtils::listFiles(LOCAL_SNAPSHOT_PATH);\n\n    for (std::list<NacosString>::iterator it = rootFile.begin(); it != rootFile.end(); it++) {\n        //endsWith(\"_nacos\")\n        if (it->length() >= 6 && (it->rfind(\"_nacos\") == it->length() - 6)) {\n            IOUtils::cleanDirectory(LOCAL_SNAPSHOT_PATH + \"/\" + *it);\n        }\n    }\n    //LOGGER.error(\"clean all snapshot error, \" + ioe.toString(), ioe);\n};\n\nvoid LocalSnapshotManager::cleanEnvSnapshot(const NacosString &envName) {\n    NacosString tmp = LOCAL_SNAPSHOT_PATH + \"/\" + envName + \"_nacos\";\n    tmp += \"/snapshot\";\n    //I think we should remove -tenant also, so for one envname, cache for all tenants within the environment will be purged\n    NacosString tmp_tenant = tmp + \"-tenant\";\n    IOUtils::cleanDirectory(tmp);\n    IOUtils::cleanDirectory(tmp_tenant);\n    log_info(\"[LocalSnapshotManager]-cleanEnvSnapshot:success delete %s-snapshot: %s\\n\", envName.c_str(), tmp.c_str());\n};\n\nNacosString LocalSnapshotManager::getFailoverFile(const NacosString &serverName, const NacosString &dataId,\n                                                      const NacosString &group, const NacosString &tenant) {\n    NacosString Failoverfile = LOCAL_SNAPSHOT_PATH + \"/\" + serverName + \"_nacos\";\n    Failoverfile += \"/data\";\n    if (ParamUtils::isBlank(tenant)) {\n        Failoverfile += \"/config-data\";\n    } else {\n        Failoverfile += \"/config-data-tenant/\";\n        Failoverfile += tenant;\n    }\n    if (NacosStringOps::isNullStr(group)) {\n        Failoverfile += \"/\" + ConfigConstant::DEFAULT_GROUP + \"/\" + dataId;\n    } else {\n        Failoverfile += \"/\" + group + \"/\" + dataId;\n    }\n    return Failoverfile;\n};\n\nNacosString LocalSnapshotManager::getSnapshotFile(const NacosString &envName, const NacosString &dataId,\n                                                      const NacosString &group, const NacosString &tenant) {\n    NacosString filename = LOCAL_SNAPSHOT_PATH + \"/\" + envName + \"_nacos\";\n    if (isNull(tenant)) {\n        filename += \"/snapshot\";\n    } else {\n        filename += \"/snapshot-tenant/\" + tenant;\n    }\n\n    if (NacosStringOps::isNullStr(group)) {\n        filename += \"/\" + ConfigConstant::DEFAULT_GROUP + \"/\" + dataId;\n    } else {\n        filename += \"/\" + group + \"/\" + dataId;\n    }\n    return filename;\n};\n\nLocalSnapshotManager::LocalSnapshotManager(AppConfigManager *appConfigManager) {\n    this->_appCfgMgr = appConfigManager;\n    LOCAL_SNAPSHOT_PATH = _appCfgMgr->get(PropertyKeyConst::NACOS_SNAPSHOT_PATH);\n    LOCAL_FAILOVER_PATH = _appCfgMgr->get(PropertyKeyConst::NACOS_SNAPSHOT_PATH);\n\n    log_debug(\"LocalConfigInfoProcessor::LocalConfigInfoProcessor() LOCAL_SNAPSHOT_PATH = %s\\n\", LocalSnapshotManager::LOCAL_SNAPSHOT_PATH.c_str());\n}\n}//namespace nacos"
  },
  {
    "path": "src/config/LocalSnapshotManager.h",
    "content": "#ifndef __LOCAL_SNAPSHOT_MGR_H_\n#define __LOCAL_SNAPSHOT_MGR_H_\n\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"src/config/AppConfigManager.h\"\n#include \"Compatibility.h\"\n\n/**\n * Snapshot/Failover manager\n *\n * @author Nacos\n */\n\nnamespace nacos{\nclass LocalSnapshotManager {\nprivate:\n    AppConfigManager *_appCfgMgr;\n    NacosString LOCAL_SNAPSHOT_PATH;\n    NacosString LOCAL_FAILOVER_PATH;\npublic:\n\n    LocalSnapshotManager(AppConfigManager *appConfigManager);\n\n    NacosString getFailover(const NacosString &serverName, const NacosString &dataId, const NacosString &group,\n                                   const NacosString &tenant);\n\n    /**\n     * Accuire local cache content, returns NULLSTR when the file does not exist or an exception is thrown\n     * 获取本地缓存文件内容。NULL表示没有本地文件或抛出异常。\n     */\n    NacosString getSnapshot(const NacosString &name, const NacosString &dataId, const NacosString &group,\n                                   const NacosString &tenant);\n\n    NacosString readFile(const NacosString &file) NACOS_THROW(IOException);\n\n    void saveSnapshot(const NacosString &envName, const NacosString &dataId, const NacosString &group,\n                             const NacosString &tenant, const NacosString &config);\n\n    /**\n     * Purge all cached files in snapshot directory\n     * 清除snapshot目录下所有缓存文件。\n     */\n    void cleanAllSnapshot();\n\n    void cleanEnvSnapshot(const NacosString &envName);\n\n    NacosString\n    getFailoverFile(const NacosString &serverName, const NacosString &dataId, const NacosString &group,\n                    const NacosString &tenant);\n\n    NacosString getSnapshotFile(const NacosString &envName, const NacosString &dataId, const NacosString &group,\n                                       const NacosString &tenant);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/config/NacosConfigService.cpp",
    "content": "#include \"NacosConfigService.h\"\r\n#include \"src/security/SecurityManager.h\"\r\n#include \"src/log/Logger.h\"\r\n#include \"ConfigProxy.h\"\r\n#include \"src/utils/ParamUtils.h\"\r\n\r\nusing namespace std;\r\n\r\nnamespace nacos{\r\nNacosConfigService::NacosConfigService(ObjectConfigData *objectConfigData) NACOS_THROW(NacosException) {\r\n    _objectConfigData = objectConfigData;\r\n    if (_objectConfigData->_appConfigManager->nacosAuthEnabled()) {\r\n        _objectConfigData->_securityManager->login();\r\n        _objectConfigData->_securityManager->start();\r\n    }\r\n}\r\n\r\nNacosConfigService::~NacosConfigService() {\r\n    log_debug(\"[NacosConfigService]:~NacosConfigService()\\n\");\r\n    delete _objectConfigData;\r\n}\r\n\r\nNacosString NacosConfigService::getConfig\r\n        (\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                long timeoutMs\r\n        ) NACOS_THROW(NacosException) {\r\n    return getConfigInner(getNamespace(), dataId, group, timeoutMs);\r\n}\r\n\r\nbool NacosConfigService::publishConfig\r\n        (\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                const NacosString &content\r\n        ) NACOS_THROW(NacosException) {\r\n    return publishConfigInner(getNamespace(), dataId, group, NULLSTR, NULLSTR, NULLSTR, content);\r\n}\r\n\r\nbool NacosConfigService::removeConfig\r\n        (\r\n                const NacosString &dataId,\r\n                const NacosString &group\r\n        ) NACOS_THROW(NacosException) {\r\n    return removeConfigInner(getNamespace(), dataId, group, NULLSTR);\r\n}\r\n\r\nNacosString NacosConfigService::getConfigInner\r\n        (\r\n                const NacosString &tenant,\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                long timeoutMs\r\n        ) NACOS_THROW(NacosException) {\r\n    NacosString result = NULLSTR;\r\n\r\n    AppConfigManager *_appConfigManager = _objectConfigData->_appConfigManager;\r\n    LocalSnapshotManager *_localSnapshotManager = _objectConfigData->_localSnapshotManager;\r\n\r\n    NacosString clientName = _appConfigManager->get(PropertyKeyConst::CLIENT_NAME);\r\n    result = _localSnapshotManager->getFailover(clientName.c_str(), dataId, group, tenant);\r\n    if (!NacosStringOps::isNullStr(result)) {\r\n        log_warn(\"[NacosConfigService]-getConfig:[clientName=%s] get failover ok, dataId=%s, group=%s, tenant=%s, config=%s\",\r\n                 clientName.c_str(),\r\n                 dataId.c_str(),\r\n                 group.c_str(),\r\n                 tenant.c_str(),\r\n                 result.c_str());\r\n        return result;\r\n    }\r\n\r\n    try {\r\n        result = _objectConfigData->_clientWorker->getServerConfig(tenant, dataId, group, timeoutMs);\r\n    } catch (NacosException &e) {\r\n        if (e.errorcode() == NacosException::NO_RIGHT) {\r\n            log_error(\"Invalid credential, e: %d = %s\\n\", e.errorcode(), e.what());\r\n        }\r\n        const NacosString &clientName = _appConfigManager->get(PropertyKeyConst::CLIENT_NAME);\r\n        result = _localSnapshotManager->getSnapshot(clientName, dataId, group, tenant);\r\n        if (e.errorcode() == NacosException::NO_RIGHT && NacosStringOps::isNullStr(result)) {\r\n            //permission denied and no failback, let user decide what to do\r\n            throw e;\r\n        }\r\n    }\r\n    return result;\r\n}\r\n\r\nbool NacosConfigService::removeConfigInner\r\n        (\r\n                const NacosString &tenant,\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                const NacosString &tag\r\n        ) NACOS_THROW(NacosException) {\r\n    std::list <NacosString> headers;\r\n    std::list <NacosString> paramValues;\r\n    //Get the request url\r\n    NacosString path = _objectConfigData->_appConfigManager->getContextPath() + ConfigConstant::CONFIG_CONTROLLER_PATH;\r\n\r\n    HttpResult res;\r\n\r\n    paramValues.push_back(\"dataId\");\r\n    paramValues.push_back(dataId);\r\n\r\n    NacosString parmGroupid = ParamUtils::null2defaultGroup(group);\r\n    paramValues.push_back(\"group\");\r\n    paramValues.push_back(parmGroupid);\r\n\r\n    if (!isNull(tenant)) {\r\n        paramValues.push_back(\"tenant\");\r\n        paramValues.push_back(tenant);\r\n    }\r\n\r\n    NacosString serverAddr = _objectConfigData->_serverListManager->getCurrentServerAddr();\r\n    NacosString url = serverAddr + \"/\" + path;\r\n    log_debug(\"[NacosConfigService]-removeConfigInner: Assembled URL:%s\\n\", url.c_str());\r\n\r\n    ConfigProxy *_configProxy = _objectConfigData->_configProxy;\r\n    try {\r\n        res = _configProxy->reqAPI(IHttpCli::DELETE, url, headers, paramValues, _objectConfigData->encoding, POST_TIMEOUT);\r\n    }\r\n    catch (NetworkException &e) {\r\n        log_warn(\"[NacosConfigService]-removeConfigInner: error, %s, %s, %s, msg: %s\\n\", dataId.c_str(), group.c_str(), tenant.c_str(), e.what());\r\n        return false;\r\n    }\r\n\r\n    //If the server returns true, then this call succeeds\r\n    if (res.content.compare(\"true\") == 0) {\r\n        return true;\r\n    } else {\r\n        return false;\r\n    }\r\n}\r\n\r\nbool NacosConfigService::publishConfigInner\r\n        (\r\n                const NacosString &tenant,\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                const NacosString &tag,\r\n                const NacosString &appName,\r\n                const NacosString &betaIps,\r\n                const NacosString &content\r\n        ) NACOS_THROW(NacosException) {\r\n    //TODO:More stringent check, need to improve checkParam() function\r\n    ParamUtils::checkParam(dataId, group, content);\r\n\r\n    std::list <NacosString> headers;\r\n    std::list <NacosString> paramValues;\r\n    NacosString parmGroupid;\r\n    //Get the request url\r\n    NacosString path = _objectConfigData->_appConfigManager->getContextPath() + ConfigConstant::CONFIG_CONTROLLER_PATH;\r\n\r\n    HttpResult res;\r\n\r\n    parmGroupid = ParamUtils::null2defaultGroup(group);\r\n    ParamUtils::addKV(paramValues, \"group\", parmGroupid);\r\n\r\n    ParamUtils::addKV(paramValues, \"dataId\", dataId);\r\n\r\n    ParamUtils::addKV(paramValues, \"content\", content);\r\n\r\n    if (!isNull(tenant)) {\r\n        ParamUtils::addKV(paramValues, \"tenant\", tenant);\r\n    }\r\n\r\n    if (!isNull(appName)) {\r\n        ParamUtils::addKV(paramValues, \"appName\", appName);\r\n    }\r\n\r\n    if (!isNull(tag)) {\r\n        ParamUtils::addKV(paramValues, \"tag\", tag);\r\n    }\r\n\r\n    if (!isNull(betaIps)) {\r\n        ParamUtils::addKV(paramValues, \"betaIps\", betaIps);\r\n    }\r\n\r\n    NacosString serverAddr = _objectConfigData->_serverListManager->getCurrentServerAddr();\r\n    NacosString url = serverAddr + \"/\" + path;\r\n    log_debug(\"[NacosConfigService]-publishConfigInner:httpPost Assembled URL:%s\\n\", url.c_str());\r\n\r\n    ConfigProxy *_configProxy = _objectConfigData->_configProxy;\r\n    try {\r\n        res = _configProxy->reqAPI(IHttpCli::POST, url, headers, paramValues, _objectConfigData->encoding, POST_TIMEOUT);\r\n    }\r\n    catch (NetworkException &e) {\r\n        //\r\n        log_warn(\"[NacosConfigService]-publishConfigInner: exception, dataId=%s, group=%s, msg=%s\\n\", dataId.c_str(), group.c_str(),\r\n                 tenant.c_str(), e.what());\r\n        return false;\r\n    }\r\n\r\n    //If the server returns true, then this call succeeds\r\n    if (res.content.compare(\"true\") == 0) {\r\n        return true;\r\n    } else {\r\n        return false;\r\n    }\r\n}\r\n\r\nvoid NacosConfigService::addListener\r\n        (\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                Listener *listener\r\n        ) NACOS_THROW(NacosException) {\r\n    NacosString parmgroup = ConfigConstant::DEFAULT_GROUP;\r\n    if (!isNull(group)) {\r\n        parmgroup = group;\r\n    }\r\n\r\n    //TODO:give a constant to this hard-coded number\r\n    NacosString cfgcontent;\r\n    try {\r\n        cfgcontent = getConfig(dataId, group, 3000);\r\n    } catch (NacosException &e) {\r\n        cfgcontent = \"\";\r\n    }\r\n\r\n    _objectConfigData->_clientWorker->addListener(dataId, parmgroup, getNamespace(), cfgcontent, listener);\r\n    _objectConfigData->_clientWorker->startListening();\r\n}\r\n\r\nvoid NacosConfigService::removeListener\r\n        (\r\n                const NacosString &dataId,\r\n                const NacosString &group,\r\n                Listener *listener\r\n        ) {\r\n    NacosString parmgroup = ConfigConstant::DEFAULT_GROUP;\r\n    if (!isNull(group)) {\r\n        parmgroup = group;\r\n    }\r\n    log_debug(\"[NacosConfigService]-removeListener: calling client worker\\n\");\r\n    _objectConfigData->_clientWorker->removeListener(dataId, parmgroup, getNamespace(), listener);\r\n}\r\n\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/config/NacosConfigService.h",
    "content": "#ifndef __NACOS_CFG_SVC_H_\n#define __NACOS_CFG_SVC_H_\n\n#include \"config/ConfigService.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/listen/ClientWorker.h\"\n#include \"NacosString.h\"\n#include \"src/server/ServerListManager.h\"\n#include \"Properties.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass NacosConfigService : public ConfigService {\nprivate:\n    ObjectConfigData *_objectConfigData;\n\n    //Private Methods\n    NacosConfigService();\n\n    NacosString getConfigInner(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                               long timeoutMs) NACOS_THROW(NacosException);\n\n    bool removeConfigInner(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                           const NacosString &tag) NACOS_THROW(NacosException);\n\n    bool publishConfigInner(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                            const NacosString &tag, const NacosString &appName, const NacosString &betaIps,\n                            const NacosString &content) NACOS_THROW(NacosException);\n    //NacosString monitorChange(std::map<NacosString, NacosString> &keysAndContents, long timeoutMs) throw (NacosException);\n    //static NacosString monitorListToString(std::map<NacosString, NacosString> &keysAndContents);\n\n    NacosString getNamespace() const { return _objectConfigData->_appConfigManager->get(PropertyKeyConst::NAMESPACE); };\npublic:\n    const static long POST_TIMEOUT = 3000L;\n\n    //Public Methods\n    NacosString getConfig(const NacosString &dataId, const NacosString &group, long timeoutMs) NACOS_THROW(NacosException);\n\n    bool publishConfig(const NacosString &dataId, const NacosString &group,\n                       const NacosString &content) NACOS_THROW(NacosException);\n\n    bool removeConfig(const NacosString &dataId, const NacosString &group) NACOS_THROW(NacosException);\n\n    void addListener(const NacosString &dataId, const NacosString &group, Listener *listener) NACOS_THROW(NacosException);\n\n    void removeListener(const NacosString &dataId, const NacosString &group, Listener *listener);\n\n    HttpDelegate *getHttpDelegate() const { return _objectConfigData->_httpDelegate; };\n\n    IHttpCli *getHttpCli() const { return _objectConfigData->_httpCli; };\n\n    ServerListManager *getServerListManager() const { return _objectConfigData->_serverListManager; };\n\n    ClientWorker *getClientWorker() const { return _objectConfigData->_clientWorker; };\n\n    AppConfigManager *getAppConfigManager() const { return _objectConfigData->_appConfigManager; };\n\n    void setHttpDelegate(HttpDelegate *httpDelegate) { _objectConfigData->_httpDelegate = httpDelegate; };\n\n    void setHttpCli(IHttpCli *httpCli) { _objectConfigData->_httpCli = httpCli; };\n\n    void setServerListManager(ServerListManager *svrListMgr) { _objectConfigData->_serverListManager = svrListMgr; };\n\n    void setClientWorker(ClientWorker *clientWorker) { _objectConfigData->_clientWorker = clientWorker; };\n\n    void setAppConfigManager(AppConfigManager *appConfigManager) { _objectConfigData->_appConfigManager = appConfigManager; };\n\n    //ctors/dtor\n    NacosConfigService(ObjectConfigData *objectConfigData) NACOS_THROW(NacosException);\n\n    virtual ~NacosConfigService();\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/config/SnapShotSwitch.cpp",
    "content": "#include \"LocalSnapshotManager.h\"\r\n#include \"SnapShotSwitch.h\"\r\n\r\nnamespace nacos{\r\nbool SnapShotSwitch::getIsSnapShot() {\r\n    return isSnapShot;\r\n};\r\n\r\nvoid SnapShotSwitch::setIsSnapShot(bool isSnapShot) {\r\n    SnapShotSwitch::isSnapShot = isSnapShot;\r\n    //LocalConfigInfoProcessor::cleanAllSnapshot();\r\n};\r\n}//namespace nacos"
  },
  {
    "path": "src/config/SnapShotSwitch.h",
    "content": "#ifndef __SS_SWITCH_H_\n#define __SS_SWITCH_H_\n\nnamespace nacos{\nclass SnapShotSwitch {\nprivate:\n    /**\n     * whether use local cache\n     */\n    static bool isSnapShot;\npublic:\n    static bool getIsSnapShot();\n\n    static void setIsSnapShot(bool isSnapShot);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/constant/ConfigConstant.cpp",
    "content": "#include \"constant/ConfigConstant.h\"\n\n/**\n * Constant\n *\n * @author Nacos\n */\n\nnamespace nacos{\nconst NacosString ConfigConstant::DEFAULT_GROUP = \"DEFAULT_GROUP\";\nconst NacosString ConfigConstant::DEFAULT_CONTEXT_PATH = \"nacos\";\nconst NacosString ConfigConstant::PROTOCOL_VERSION = \"v1\";\nconst NacosString ConfigConstant::GET_SERVERS_PATH = \"ns/operator/servers\";\n\nconst NacosString ConfigConstant::DATAID = \"dataId\";\n\nconst NacosString ConfigConstant::PROBE_MODIFY_REQUEST = \"Listening-Configs\";\n\nconst NacosString ConfigConstant::PROBE_MODIFY_RESPONSE = \"Probe-Modify-Response\";\n\nconst NacosString ConfigConstant::BASE_PATH = \"/v1/cs\";\n\nconst NacosString ConfigConstant::CONFIG_CONTROLLER_PATH = BASE_PATH + \"/configs\";\n\n/**\n* second\n*/\nconst int ConfigConstant::POLLING_INTERVAL_TIME = 15;\n\nconst NacosString ConfigConstant::ENCODE = \"UTF-8\";\n\nconst int ConfigConstant::FLOW_CONTROL_THRESHOLD = 20;\n\nconst NacosString ConfigConstant::LINE_SEPARATOR = \"\\x1\";\n\nconst NacosString ConfigConstant::WORD_SEPARATOR = \"\\x2\";\n\nconst NacosString ConfigConstant::NAMING_INSTANCE_ID_SPLITTER = \"#\";\n\nconst NacosString ConfigConstant::DEFAULT_CLUSTER_NAME = \"DEFAULT\";\n\nconst NacosString ConfigConstant::SERVICE_INFO_SPLITER = \"@@\";\n\nconst NacosString ConfigConstant::FILE_SEPARATOR = \"/\";\n\nconst NacosString ConfigConstant::CONFIG_NEXT_LINE = \"\\n\";\n\nconst NacosString ConfigConstant::CONFIG_KV_SEPARATOR = \"=\";\n\nconst NacosString ConfigConstant::DEFAULT_CONFIG_FILE = \"nacos-cpp-cli.properties\";\n}//namespace nacos\n"
  },
  {
    "path": "src/constant/NamingConstant.cpp",
    "content": "#include \"constant/NamingConstant.h\"\n\nnamespace nacos{\nconst NacosString NamingConstant::SERVICE_NAME = \"serviceName\";\n\nconst NacosString NamingConstant::CLUSTER_NAME = \"clusterName\";\nconst NacosString NamingConstant::UDP_PORT = \"udpPort\";\nconst NacosString NamingConstant::CLUSTERS = \"clusters\";\n\nconst NacosString NamingConstant::CLIENT_IP = \"clientIP\";\nconst NacosString NamingConstant::HEALTHY_ONLY = \"healthyOnly\";\n\nconst NacosString NamingConstant::HEALTHY = \"healthy\";\n\nconst NacosString NamingConstant::NAMESPACE_ID = \"namespaceId\";\n\nconst NacosString NamingConstant::GROUP_NAME = \"groupName\";\n\nconst NacosString NamingConstant::SPLITER = \"@@\";\n\nconst NacosString NamingConstant::EMPTY = \"\";\n\nconst NacosString NamingConstant::ALL_IPS = \"000--00-ALL_IPS--00--000\";\n\nconst NacosString NamingConstant::BEAT = \"beat\";\n\nconst NacosString NamingConstant::PAGE_SIZE = \"pageSize\";\nconst NacosString NamingConstant::PAGE_NO = \"pageNo\";\n}//namespace nacos"
  },
  {
    "path": "src/constant/PropertyKeyConst.cpp",
    "content": "#include \"constant/PropertyKeyConst.h\"\n\nnamespace nacos{\nconst NacosString PropertyKeyConst::IS_USE_ENDPOINT_PARSING_RULE = \"isUseEndpointParsingRule\";\n\nconst NacosString PropertyKeyConst::ENDPOINT = \"endpoint\";\n\nconst NacosString PropertyKeyConst::ENDPOINT_PORT = \"endpointPort\";\n\nconst NacosString PropertyKeyConst::NAMESPACE = \"namespace\";\n\nconst NacosString PropertyKeyConst::ENDPOINT_QUERY_PARAMS = \"endpointQueryParams\";\n\nconst NacosString PropertyKeyConst::ACCESS_KEY = \"accessKey\";\n\nconst NacosString PropertyKeyConst::SECRET_KEY = \"secretKey\";\n\nconst NacosString PropertyKeyConst::APP_NAME = \"appName\";\n\nconst NacosString PropertyKeyConst::RAM_ROLE_NAME = \"ramRoleName\";\n\nconst NacosString PropertyKeyConst::SERVER_ADDR = \"serverAddr\";\n\nconst NacosString PropertyKeyConst::CONTEXT_PATH = \"nacos.server.contextpath\";\n\nconst NacosString PropertyKeyConst::ENDPOINT_CONTEXT_PATH = \"endpointContextPath\";\n\nconst NacosString PropertyKeyConst::CLUSTER_NAME = \"clusterName\";\n\nconst NacosString PropertyKeyConst::ENCODE = \"encode\";\n\nconst NacosString PropertyKeyConst::NAMING_LOAD_CACHE_AT_START = \"namingLoadCacheAtStart\";\n\nconst NacosString PropertyKeyConst::NAMING_CLIENT_BEAT_THREAD_COUNT = \"namingClientBeatThreadCount\";\n\nconst NacosString PropertyKeyConst::NAMING_POLLING_THREAD_COUNT = \"namingPollingThreadCount\";\n\nconst NacosString PropertyKeyConst::SRVLISTMGR_REFRESH_INTERVAL = \"serverListMgr.refreshInterval\";\n\nconst NacosString PropertyKeyConst::SERVER_REQ_TIMEOUT = \"nacos.server.reqtimeout\";\n\nconst NacosString PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL = \"naming.poller.interval\";\n\nconst NacosString PropertyKeyConst::UDP_RECEIVER_PORT = \"nacos.udp.port\";\n\nconst NacosString PropertyKeyConst::CONFIG_LONGPULLLING_TIMEOUT = \"config.longpulling.timeout\";\n\nconst NacosString PropertyKeyConst::HB_FAIL_WAIT_TIME = \"naming.heartbeat.failwait\";\nconst NacosString PropertyKeyConst::NACOS_SNAPSHOT_PATH = \"nacos.snapshot.path\";\n\nconst NacosString PropertyKeyConst::LOG_PATH = \"nacos.log.path\";\nconst NacosString PropertyKeyConst::LOG_ROTATE_SIZE = \"nacos.log.rotateSize\";\nconst NacosString PropertyKeyConst::LOG_LEVEL = \"nacos.log.level\";\n\nconst NacosString PropertyKeyConst::CLIENT_NAME = \"nacos.client.name\";\nconst NacosString PropertyKeyConst::AUTH_USERNAME = \"nacos.auth.username\";\nconst NacosString PropertyKeyConst::AUTH_PASSWORD = \"nacos.auth.password\";\nconst NacosString PropertyKeyConst::LOCAL_IP = \"nacos.client.ip\";\nconst NacosString PropertyKeyConst::INSTANCE_ID_SEQ_FILE = \"nacos.instId.seq.file\";\nconst NacosString PropertyKeyConst::INSTANCE_ID_PREFIX = \"nacos.instId.prefix\";\n}//namespace nacos\n"
  },
  {
    "path": "src/constant/UtilAndComs.cpp",
    "content": "#include \"constant/UtilAndComs.h\"\n\nnamespace nacos{\nNacosString UtilAndComs::VERSION = \"Nacos-C-Client:v1.0.21\";//TODO:fix nacos trunk code for cpp client\n\nNacosString UtilAndComs::ENCODING = \"UTF-8\";\n\nNacosString UtilAndComs::NACOS_URL_BASE = \"/v1/ns\";\n\nNacosString UtilAndComs::NACOS_URL_INSTANCE = NACOS_URL_BASE + \"/instance\";\n\nint UtilAndComs::REQUEST_DOMAIN_RETRY_COUNT = 3;\n\nNacosString UtilAndComs::SERVER_ADDR_IP_SPLITER = \":\";\n\nint UtilAndComs::DEFAULT_CLIENT_BEAT_THREAD_COUNT = 4;//TODO:Calc this according to nr_processors of the host\n\nint UtilAndComs::DEFAULT_POLLING_THREAD_COUNT = 1;//TODO:Calc this according to nr_processors of the host\n\n//Underlying logic:\n/*int UtilAndComs::DEFAULT_CLIENT_BEAT_THREAD_COUNT = Runtime.getRuntime()\n.availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2\n: 1;\n\nint UtilAndComs::DEFAULT_POLLING_THREAD_COUNT = Runtime.getRuntime()\n.availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2\n: 1;*/\n\nvoid UtilAndComs::Init() {\n\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/crypto/MACProvider.cpp",
    "content": "//\n// Created by liuhanyu on 2021/7/8.\n//\n\n#include \"MACProvider.h\"\n#include \"src/crypto/hmac_sha1/hmac/hmac.h\"\n\nnamespace nacos {\n\nstd::map<int, IMAC*> *MACProvider::MACRegistry;\nconst int MACProvider::HMAC_SHA1;\n\nclass HMACSha1 : public IMAC {\npublic:\n    void getMac(const void *k,   /* secret key */\n                size_t lk,  /* length of the key in bytes */\n                const void *d,   /* data */\n                size_t ld,  /* length of data in bytes */\n                void *out, /* output buffer, at least \"t\" bytes */\n                size_t *t);\n};\n\nvoid HMACSha1::getMac(const void *k,   /* secret key */\n                      size_t lk,  /* length of the key in bytes */\n                      const void *d,   /* data */\n                      size_t ld,  /* length of data in bytes */\n                      void *out, /* output buffer, at least \"t\" bytes */\n                      size_t *t) {\n    hmac_sha1((const uint8_t*)k, lk, (const uint8_t*)d, ld, (uint8_t*)out, t);\n}\n\nvoid MACProvider::Init() {\n    MACRegistry = new std::map<int, IMAC*>();\n    (*MACRegistry)[MACProvider::HMAC_SHA1] = new HMACSha1();\n}\n\nvoid MACProvider::DeInit() {\n    for (std::map<int, IMAC*>::iterator it = MACRegistry->begin(); it != MACRegistry->end(); it++) {\n        IMAC * curMACProvider = it->second;\n        delete curMACProvider;\n    }\n\n    delete MACRegistry;\n}\n\nIMAC *MACProvider::getMAC(int algorithm) {\n    if (MACRegistry->count(algorithm) > 0) {\n        return (*MACRegistry)[algorithm];\n    }\n\n    return NULL;\n}\n\n}\n"
  },
  {
    "path": "src/crypto/MACProvider.h",
    "content": "//\n// Created by liuhanyu on 2021/7/8.\n//\n\n#ifndef NACOS_SDK_CPP_MACPROVIDER_H\n#define NACOS_SDK_CPP_MACPROVIDER_H\n#include \"NacosString.h\"\n#include <map>\n\nnamespace nacos {\n\nclass IMAC {\npublic:\n    virtual void getMac(const void *k,   /* secret key */\n                size_t lk,  /* length of the key in bytes */\n                const void *d,   /* data */\n                size_t ld,  /* length of data in bytes */\n                void *out, /* output buffer, at least \"t\" bytes */\n                size_t *t) = 0;\n    virtual ~IMAC() {};\n};\n\nclass MACProvider {\nprivate:\n    static std::map<int, IMAC*> *MACRegistry;\npublic:\n    static void Init();\n    static void DeInit();\n    static IMAC *getMAC(int algorithm);\n    static const int HMAC_SHA1 = 930620;\n};\n\n}\n\n#endif //NACOS_SDK_CPP_MACPROVIDER_H\n"
  },
  {
    "path": "src/crypto/SignatureTool.h",
    "content": "//\n// Created by liuhanyu on 2021/7/8.\n//\n\n#ifndef SIGNATURE_TOOL\n#define SIGNATURE_TOOL\n\n#include \"NacosString.h\"\n#include \"MACProvider.h\"\n#include \"base64/base64.h\"\n#include \"src/debug/DebugAssertion.h\"\n\nnamespace nacos {\n\n/**\n * SignatureTool\n *\n * @author Liu, Hanyu\n * Signature tool\n */\nclass SignatureTool {\npublic:\n    //Returns a base64-encoded signature string\n    static NacosString SignWithHMAC_SHA1(const NacosString &dataToSign, const NacosString &secretKey) {\n        IMAC *digester = MACProvider::getMAC(MACProvider::HMAC_SHA1);\n        unsigned char signature[20];\n        size_t outlen = sizeof(signature);\n        digester->getMac(secretKey.c_str(), secretKey.length(), dataToSign.c_str(), dataToSign.length(), (void*)signature, &outlen);\n        NACOS_ASSERT(outlen == 20);//must be 20 since we're using HMAC_SHA1\n        NacosString encoded_signature = base64_encode(signature, sizeof(signature));\n        return encoded_signature;\n    }\n};\n\n}\n#endif //NACOS_SDK_CPP_MACPROVIDER_H\n"
  },
  {
    "path": "src/crypto/base64/base64.h",
    "content": "/*\n* Base64 encoding/decoding (RFC1341)\n* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>\n*\n* This software may be distributed under the terms of the BSD license.\n* See README for more details.\n*/\n\n// 2016-12-12 - Gaspard Petit : Slightly modified to return a std::string\n// instead of a buffer allocated with malloc.\n\n#include <string>\n\nnamespace nacos {\n\n\nstatic const unsigned char base64_table[65] =\n        \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n/**\n* base64_encode - Base64 encode\n* @src: Data to be encoded\n* @len: Length of the data to be encoded\n* @out_len: Pointer to output length variable, or %NULL if not used\n* Returns: Allocated buffer of out_len bytes of encoded data,\n* or empty string on failure\n*/\nstatic std::string base64_encode(const unsigned char *src, size_t len)\n{\n    unsigned char *out, *pos;\n    const unsigned char *end, *in;\n\n    size_t olen;\n\n    olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */\n\n    if (olen < len)\n        return std::string(); /* integer overflow */\n\n    std::string outStr;\n    outStr.resize(olen);\n    out = (unsigned char*)&outStr[0];\n\n    end = src + len;\n    in = src;\n    pos = out;\n    while (end - in >= 3) {\n        *pos++ = base64_table[in[0] >> 2];\n        *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];\n        *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];\n        *pos++ = base64_table[in[2] & 0x3f];\n        in += 3;\n    }\n\n    if (end - in) {\n        *pos++ = base64_table[in[0] >> 2];\n        if (end - in == 1) {\n            *pos++ = base64_table[(in[0] & 0x03) << 4];\n            *pos++ = '=';\n        }\n        else {\n            *pos++ = base64_table[((in[0] & 0x03) << 4) |\n                                  (in[1] >> 4)];\n            *pos++ = base64_table[(in[1] & 0x0f) << 2];\n        }\n        *pos++ = '=';\n    }\n\n    return outStr;\n}\n\n}"
  },
  {
    "path": "src/crypto/hmac_sha1/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Bob Liu\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"
  },
  {
    "path": "src/crypto/hmac_sha1/README.md",
    "content": "hmac-sha1\n=========\n\n[![Build Status](https://travis-ci.org/Akagi201/hmac-sha1.svg)](https://travis-ci.org/Akagi201/hmac-sha1)\n\nStandalone implementation of `HMAC()` + `EVP_sha1()` in `OpenSSL`\n\n## API\n\n```\n#include \"hmac/hmac.h\"\n\nvoid hmac_sha1(const uint8_t *k,   /* secret key */\n        size_t lk,  /* length of the key in bytes */\n        const uint8_t *d,   /* data */\n        size_t ld,  /* length of data in bytes */\n        uint8_t *out, /* output buffer, at least \"t\" bytes */\n        size_t *t);\n```"
  },
  {
    "path": "src/crypto/hmac_sha1/hmac/hmac.h",
    "content": "/**\n* @file re_hmac.h  Interface to HMAC functions\n*\n* Copyright (C) 2010 Creytiv.com\n*/\n\n#ifndef HMAC_H_\n#define HMAC_H_ (1)\n\n#include <stdint.h>\n\nvoid hmac_sha1(const uint8_t *k,   /* secret key */\n        size_t lk,  /* length of the key in bytes */\n        const uint8_t *d,   /* data */\n        size_t ld,  /* length of data in bytes */\n        uint8_t *out, /* output buffer, at least \"t\" bytes */\n        size_t *t);\n\n#endif // HMAC_H_\n"
  },
  {
    "path": "src/crypto/hmac_sha1/hmac/hmac_sha1.cpp",
    "content": "/**\n* @file hmac_sha1.c  Implements HMAC-SHA1 as of RFC 2202\n*\n* Copyright (C) 2010 Creytiv.com\n*/\n#include <string.h>\n#include <stdint.h>\n\n#ifdef USE_OPENSSL\n#include <openssl/sha.h>\n#include <openssl/hmac.h>\n#include <openssl/err.h>\n#else\n\n#include \"../sha/sha.h\"\n\n#endif\n\n#include \"hmac.h\"\n\n\n/** SHA-1 Block size */\n#ifndef SHA_BLOCKSIZE\n#define SHA_BLOCKSIZE   (64)\n#endif\n\n\n/**\n* Function to compute the digest\n*\n* @param k   Secret key\n* @param lk  Length of the key in bytes\n* @param d   Data\n* @param ld  Length of data in bytes\n* @param out Digest output\n* @param t   Size of digest output\n*/\nvoid hmac_sha1(const uint8_t *k,  /* secret key */\n        size_t lk,       /* length of the key in bytes */\n        const uint8_t *d,  /* data */\n        size_t ld,       /* length of data in bytes */\n        uint8_t *out,      /* output buffer, at least \"t\" bytes */\n        size_t *t) {\n#ifdef USE_OPENSSL\n\n\tif (!HMAC(EVP_sha1(), k, (int)lk, d, ld, out, t)) {\n\t\tERR_clear_error();\n\t}\n#else\n    SHA_CTX ictx, octx;\n    uint8_t isha[SHA_DIGEST_LENGTH], osha[SHA_DIGEST_LENGTH];\n    uint8_t key[SHA_DIGEST_LENGTH];\n    uint8_t buf[SHA_BLOCKSIZE];\n    size_t i;\n\n    if (lk > SHA_BLOCKSIZE) {\n        SHA_CTX tctx;\n\n        SHA1_Init(&tctx);\n        SHA1_Update(&tctx, k, lk);\n        SHA1_Final(key, &tctx);\n\n        k = key;\n        lk = SHA_DIGEST_LENGTH;\n    }\n\n    /**** Inner Digest ****/\n\n    SHA1_Init(&ictx);\n\n    /* Pad the key for inner digest */\n    for (i = 0; i < lk; ++i) {\n        buf[i] = k[i] ^ 0x36;\n    }\n    for (i = lk; i < SHA_BLOCKSIZE; ++i) {\n        buf[i] = 0x36;\n    }\n\n    SHA1_Update(&ictx, buf, SHA_BLOCKSIZE);\n    SHA1_Update(&ictx, d, ld);\n\n    SHA1_Final(isha, &ictx);\n\n    /**** Outer Digest ****/\n\n    SHA1_Init(&octx);\n\n    /* Pad the key for outter digest */\n\n    for (i = 0; i < lk; ++i) {\n        buf[i] = k[i] ^ 0x5c;\n    }\n    for (i = lk; i < SHA_BLOCKSIZE; ++i) {\n        buf[i] = 0x5c;\n    }\n\n    SHA1_Update(&octx, buf, SHA_BLOCKSIZE);\n    SHA1_Update(&octx, isha, SHA_DIGEST_LENGTH);\n\n    SHA1_Final(osha, &octx);\n\n    /* truncate and print the results */\n    *t = *t > SHA_DIGEST_LENGTH ? SHA_DIGEST_LENGTH : *t;\n    memcpy(out, osha, *t);\n#endif\n}\n"
  },
  {
    "path": "src/crypto/hmac_sha1/sha/sha.h",
    "content": "/**\n* @file re_sha.h  Interface to SHA (Secure Hash Standard) functions\n*\n* Copyright (C) 2010 Creytiv.com\n*/\n\n#ifndef SHA_H_\n#define SHA_H_ (1)\n\n#ifdef USE_OPENSSL\n#include <openssl/sha.h>\n#else\n\n/* public api for steve reid's public domain SHA-1 implementation */\n/* this file is in the public domain */\n\n/** SHA-1 Context */\ntypedef struct {\n    uint32_t state[5];\n    /**< Context state */\n    uint32_t count[2];\n    /**< Counter       */\n    uint8_t buffer[64]; /**< SHA-1 buffer  */\n} SHA1_CTX;\n\n/** SHA-1 Context (OpenSSL compat) */\ntypedef SHA1_CTX SHA_CTX;\n\n/** SHA-1 Digest size in bytes */\n#define SHA1_DIGEST_SIZE 20\n/** SHA-1 Digest size in bytes (OpenSSL compat) */\n#define SHA_DIGEST_LENGTH SHA1_DIGEST_SIZE\n\nvoid SHA1_Init(SHA1_CTX *context);\n\nvoid SHA1_Update(SHA1_CTX *context, const void *p, size_t len);\n\nvoid SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA1_CTX *context);\n\n#endif\n\n#endif // SHA_H_\n"
  },
  {
    "path": "src/crypto/hmac_sha1/sha/sha1.cpp",
    "content": "/**\n* @file sha1.c SHA-1 in C\n*/\n\n/*\nBy Steve Reid <sreid@sea-to-sky.net>\n100% Public Domain\n\n-----------------\nModified 7/98\nBy James H. Brown <jbrown@burgoyne.com>\nStill 100% Public Domain\n\nCorrected a problem which generated improper hash values on 16 bit machines\nRoutine SHA1Update changed from\n\tvoid SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int\nlen)\nto\n\tvoid SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned\nlong len)\n\nThe 'len' parameter was declared an int which works fine on 32 bit machines.\nHowever, on 16 bit machines an int is too small for the shifts being done\nagainst\nit.  This caused the hash function to generate incorrect values if len was\ngreater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().\n\nSince the file IO in main() reads 16K at a time, any file 8K or larger would\nbe guaranteed to generate the wrong hash (e.g. Test Vector #3, a million\n\"a\"s).\n\nI also changed the declaration of variables i & j in SHA1Update to\nunsigned long from unsigned int for the same reason.\n\nThese changes should make no difference to any 32 bit implementations since\nan\nint and a long are the same size in those environments.\n\n--\nI also corrected a few compiler warnings generated by Borland C.\n1. Added #include <process.h> for exit() prototype\n2. Removed unused variable 'j' in SHA1Final\n3. Changed exit(0) to return(0) at end of main.\n\nALL changes I made can be located by searching for comments containing 'JHB'\n-----------------\nModified 8/98\nBy Steve Reid <sreid@sea-to-sky.net>\nStill 100% public domain\n\n1- Removed #include <process.h> and used return() instead of exit()\n2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)\n3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net\n\n-----------------\nModified 4/01\nBy Saul Kravitz <Saul.Kravitz@celera.com>\nStill 100% PD\nModified to run on Compaq Alpha hardware.\n\n-----------------\nModified 07/2002\nBy Ralph Giles <giles@artofcode.com>\nStill 100% public domain\nmodified for use with stdint types, autoconf\ncode cleanup, removed attribution comments\nswitched SHA1Final() argument order for consistency\nuse SHA1_ prefix for public api\nmove public api to sha1.h\n*/\n\n/*\nTest Vectors (from FIPS PUB 180-1)\n\"abc\"\n  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D\n\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\"\n  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1\nA million repetitions of \"a\"\n  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F\n*/\n\n#define SHA1HANDSOFF (1)\n\n#include <stdint.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <stdio.h>\n#include <string.h>\n#include \"sha.h\"\n\nvoid SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);\n\n#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))\n\n#if defined (BYTE_ORDER) && defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN)\n#define WORDS_BIGENDIAN 1\n#endif\n#ifdef _BIG_ENDIAN\n#define WORDS_BIGENDIAN 1\n#endif\n\n\n/* blk0() and blk() perform the initial expand. */\n/* I got the idea of expanding during the round function from SSLeay */\n/* FIXME: can we do this in an endian-proof way? */\n#ifdef WORDS_BIGENDIAN\n#define blk0(i) block->l[i]\n#else\n#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xff00ff00) \\\n         |(rol(block->l[i],8)&0x00ff00ff))\n#endif\n#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \\\n                     ^block->l[(i+2)&15]^block->l[i&15],1))\n\n/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */\n#define R0(v, w, x, y, z, i) \\\n    z+=((w&(x^y))^y)+blk0(i)+0x5a827999+rol(v,5);w=rol(w,30);\n#define R1(v, w, x, y, z, i) \\\n    z+=((w&(x^y))^y)+blk(i)+0x5a827999+rol(v,5);w=rol(w,30);\n#define R2(v, w, x, y, z, i) \\\n    z+=(w^x^y)+blk(i)+0x6ed9eba1+rol(v,5);w=rol(w,30);\n#define R3(v, w, x, y, z, i) \\\n    z+=(((w|x)&y)|(w&x))+blk(i)+0x8f1bbcdc+rol(v,5);w=rol(w,30);\n#define R4(v, w, x, y, z, i) \\\n    z+=(w^x^y)+blk(i)+0xca62c1d6+rol(v,5);w=rol(w,30);\n\n\n/* Hash a single 512-bit block. This is the core of the algorithm. */\nvoid SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) {\n    uint32_t a, b, c, d, e;\n    typedef union {\n        uint8_t c[64];\n        uint32_t l[16];\n    } CHAR64LONG16;\n    CHAR64LONG16 *block;\n\n#ifdef SHA1HANDSOFF\n    CHAR64LONG16 workspace;\n    block = &workspace;\n    memcpy(block, buffer, 64);\n#else\n\tblock = (CHAR64LONG16*)buffer;\n#endif\n\n    /* Copy context->state[] to working vars */\n    a = state[0];\n    b = state[1];\n    c = state[2];\n    d = state[3];\n    e = state[4];\n\n    /* 4 rounds of 20 operations each. Loop unrolled. */\n    R0(a, b, c, d, e, 0);\n    R0(e, a, b, c, d, 1);\n    R0(d, e, a, b, c, 2);\n    R0(c, d, e, a, b, 3);\n    R0(b, c, d, e, a, 4);\n    R0(a, b, c, d, e, 5);\n    R0(e, a, b, c, d, 6);\n    R0(d, e, a, b, c, 7);\n    R0(c, d, e, a, b, 8);\n    R0(b, c, d, e, a, 9);\n    R0(a, b, c, d, e, 10);\n    R0(e, a, b, c, d, 11);\n    R0(d, e, a, b, c, 12);\n    R0(c, d, e, a, b, 13);\n    R0(b, c, d, e, a, 14);\n    R0(a, b, c, d, e, 15);\n    R1(e, a, b, c, d, 16);\n    R1(d, e, a, b, c, 17);\n    R1(c, d, e, a, b, 18);\n    R1(b, c, d, e, a, 19);\n    R2(a, b, c, d, e, 20);\n    R2(e, a, b, c, d, 21);\n    R2(d, e, a, b, c, 22);\n    R2(c, d, e, a, b, 23);\n    R2(b, c, d, e, a, 24);\n    R2(a, b, c, d, e, 25);\n    R2(e, a, b, c, d, 26);\n    R2(d, e, a, b, c, 27);\n    R2(c, d, e, a, b, 28);\n    R2(b, c, d, e, a, 29);\n    R2(a, b, c, d, e, 30);\n    R2(e, a, b, c, d, 31);\n    R2(d, e, a, b, c, 32);\n    R2(c, d, e, a, b, 33);\n    R2(b, c, d, e, a, 34);\n    R2(a, b, c, d, e, 35);\n    R2(e, a, b, c, d, 36);\n    R2(d, e, a, b, c, 37);\n    R2(c, d, e, a, b, 38);\n    R2(b, c, d, e, a, 39);\n    R3(a, b, c, d, e, 40);\n    R3(e, a, b, c, d, 41);\n    R3(d, e, a, b, c, 42);\n    R3(c, d, e, a, b, 43);\n    R3(b, c, d, e, a, 44);\n    R3(a, b, c, d, e, 45);\n    R3(e, a, b, c, d, 46);\n    R3(d, e, a, b, c, 47);\n    R3(c, d, e, a, b, 48);\n    R3(b, c, d, e, a, 49);\n    R3(a, b, c, d, e, 50);\n    R3(e, a, b, c, d, 51);\n    R3(d, e, a, b, c, 52);\n    R3(c, d, e, a, b, 53);\n    R3(b, c, d, e, a, 54);\n    R3(a, b, c, d, e, 55);\n    R3(e, a, b, c, d, 56);\n    R3(d, e, a, b, c, 57);\n    R3(c, d, e, a, b, 58);\n    R3(b, c, d, e, a, 59);\n    R4(a, b, c, d, e, 60);\n    R4(e, a, b, c, d, 61);\n    R4(d, e, a, b, c, 62);\n    R4(c, d, e, a, b, 63);\n    R4(b, c, d, e, a, 64);\n    R4(a, b, c, d, e, 65);\n    R4(e, a, b, c, d, 66);\n    R4(d, e, a, b, c, 67);\n    R4(c, d, e, a, b, 68);\n    R4(b, c, d, e, a, 69);\n    R4(a, b, c, d, e, 70);\n    R4(e, a, b, c, d, 71);\n    R4(d, e, a, b, c, 72);\n    R4(c, d, e, a, b, 73);\n    R4(b, c, d, e, a, 74);\n    R4(a, b, c, d, e, 75);\n    R4(e, a, b, c, d, 76);\n    R4(d, e, a, b, c, 77);\n    R4(c, d, e, a, b, 78);\n    R4(b, c, d, e, a, 79);\n\n    /* Add the working vars back into context.state[] */\n    state[0] += a;\n    state[1] += b;\n    state[2] += c;\n    state[3] += d;\n    state[4] += e;\n\n    /* Wipe variables */\n    a = b = c = d = e = 0;\n}\n\n\n/**\n* Initialize new context\n*\n* @param context SHA1-Context\n*/\nvoid SHA1_Init(SHA1_CTX *context) {\n    /* SHA1 initialization constants */\n    context->state[0] = 0x67452301;\n    context->state[1] = 0xefcdab89;\n    context->state[2] = 0x98badcfe;\n    context->state[3] = 0x10325476;\n    context->state[4] = 0xc3d2e1f0;\n    context->count[0] = context->count[1] = 0;\n}\n\n\n/**\n* Run your data through this\n*\n* @param context SHA1-Context\n* @param p       Buffer to run SHA1 on\n* @param len     Number of bytes\n*/\nvoid SHA1_Update(SHA1_CTX *context, const void *p, size_t len) {\n    const uint8_t *data = (const uint8_t *)p;\n    size_t i, j;\n\n    j = (context->count[0] >> 3) & 63;\n    if ((context->count[0] += (uint32_t) (len << 3)) < (len << 3)) {\n        context->count[1]++;\n    }\n    context->count[1] += (uint32_t) (len >> 29);\n    if ((j + len) > 63) {\n        memcpy(&context->buffer[j], data, (i = 64 - j));\n        SHA1_Transform(context->state, context->buffer);\n        for (; i + 63 < len; i += 64) {\n            SHA1_Transform(context->state, data + i);\n        }\n        j = 0;\n    }\n    else i = 0;\n    memcpy(&context->buffer[j], &data[i], len - i);\n}\n\n\n/**\n* Add padding and return the message digest\n*\n* @param digest  Generated message digest\n* @param context SHA1-Context\n*/\nvoid SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA1_CTX *context) {\n    uint32_t i;\n    uint8_t finalcount[8];\n\n    for (i = 0; i < 8; i++) {\n        finalcount[i] = (uint8_t) ((context->count[(i >= 4 ? 0 : 1)]\n                >> ((3 - (i & 3)) * 8)) & 255);\n    }\n    SHA1_Update(context, (uint8_t *) \"\\200\", 1);\n    while ((context->count[0] & 504) != 448) {\n        SHA1_Update(context, (uint8_t *) \"\\0\", 1);\n    }\n    SHA1_Update(context, finalcount, 8); /* Should cause SHA1_Transform */\n    for (i = 0; i < SHA1_DIGEST_SIZE; i++) {\n        digest[i] = (uint8_t)\n                ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);\n    }\n\n    /* Wipe variables */\n    i = 0;\n    memset(context->buffer, 0, 64);\n    memset(context->state, 0, 20);\n    memset(context->count, 0, 8);\n    memset(finalcount, 0, 8);    /* SWR */\n\n#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */\n    SHA1_Transform(context->state, context->buffer);\n#endif\n}\n"
  },
  {
    "path": "src/crypto/md5/md5.cpp",
    "content": "#include \"md5.h\"\n\nusing namespace std;\n\n/* Constants for MD5Transform routine. */\n#define S11 7\n#define S12 12\n#define S13 17\n#define S14 22\n#define S21 5\n#define S22 9\n#define S23 14\n#define S24 20\n#define S31 4\n#define S32 11\n#define S33 16\n#define S34 23\n#define S41 6\n#define S42 10\n#define S43 15\n#define S44 21\n\n\n/* F, G, H and I are basic MD5 functions.\n*/\n#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\n#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n#define I(x, y, z) ((y) ^ ((x) | (~z)))\n\n/* ROTATE_LEFT rotates x left n bits.\n*/\n#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))\n\n/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.\nRotation is separate from addition to prevent recomputation.\n*/\n#define FF(a, b, c, d, x, s, ac) { \\\n(a) += F ((b), (c), (d)) + (x) + ac; \\\n(a) = ROTATE_LEFT ((a), (s)); \\\n(a) += (b); \\\n}\n#define GG(a, b, c, d, x, s, ac) { \\\n(a) += G ((b), (c), (d)) + (x) + ac; \\\n(a) = ROTATE_LEFT ((a), (s)); \\\n(a) += (b); \\\n}\n#define HH(a, b, c, d, x, s, ac) { \\\n(a) += H ((b), (c), (d)) + (x) + ac; \\\n(a) = ROTATE_LEFT ((a), (s)); \\\n(a) += (b); \\\n}\n#define II(a, b, c, d, x, s, ac) { \\\n(a) += I ((b), (c), (d)) + (x) + ac; \\\n(a) = ROTATE_LEFT ((a), (s)); \\\n(a) += (b); \\\n}\n\n\nnamespace nacos{\nconst byte MD5::PADDING[64] = {0x80};\nconst char MD5::HEX[16] = {\n        '0', '1', '2', '3',\n        '4', '5', '6', '7',\n        '8', '9', 'a', 'b',\n        'c', 'd', 'e', 'f'\n};\n\n\n/* Default construct. */\nMD5::MD5() {\n    reset();\n}\n\n/* Construct a MD5 object with a input buffer. */\nMD5::MD5(const void *input, size_t length) {\n    reset();\n    update(input, length);\n}\n\n/* Construct a MD5 object with a string. */\nMD5::MD5(const NacosString &str) {\n    reset();\n    update(str);\n}\n\n/* Construct a MD5 object with a file. */\nMD5::MD5(ifstream &in) {\n    reset();\n    update(in);\n}\n\n/* Return the message-digest */\nconst byte *MD5::digest() {\n    if (!_finished) {\n        _finished = true;\n        final();\n    }\n    return _digest;\n}\n\n/* Reset the calculate state */\nvoid MD5::reset() {\n    _finished = false;\n    /* reset number of bits. */\n    _count[0] = _count[1] = 0;\n    /* Load magic initialization constants. */\n    _state[0] = 0x67452301;\n    _state[1] = 0xefcdab89;\n    _state[2] = 0x98badcfe;\n    _state[3] = 0x10325476;\n}\n\n/* Updating the context with a input buffer. */\nvoid MD5::update(const void *input, size_t length) {\n    update((const byte *) input, length);\n}\n\n/* Updating the context with a string. */\nvoid MD5::update(const NacosString &str) {\n    update((const byte *) str.c_str(), str.length());\n}\n\n/* Updating the context with a file. */\nvoid MD5::update(ifstream &in) {\n\n    if (!in) {\n        return;\n    }\n\n    std::streamsize length;\n    char buffer[BUFFER_SIZE];\n    while (!in.eof()) {\n        in.read(buffer, BUFFER_SIZE);\n        length = in.gcount();\n        if (length > 0) {\n            update(buffer, length);\n        }\n    }\n    in.close();\n}\n\n/* MD5 block update operation. Continues an MD5 message-digest\noperation, processing another message block, and updating the\ncontext.\n*/\nvoid MD5::update(const byte *input, size_t length) {\n\n    uint32 i, index, partLen;\n\n    _finished = false;\n\n    /* Compute number of bytes mod 64 */\n    index = (uint32)((_count[0] >> 3) & 0x3f);\n\n    /* update number of bits */\n    if ((_count[0] += ((uint32) length << 3)) < ((uint32) length << 3)) {\n        ++_count[1];\n    }\n    _count[1] += ((uint32) length >> 29);\n\n    partLen = 64 - index;\n\n    /* transform as many times as possible. */\n    if (length >= partLen) {\n\n        memcpy(&_buffer[index], input, partLen);\n        transform(_buffer);\n\n        for (i = partLen; i + 63 < length; i += 64) {\n            transform(&input[i]);\n        }\n        index = 0;\n\n    } else {\n        i = 0;\n    }\n\n    /* Buffer remaining input */\n    memcpy(&_buffer[index], &input[i], length - i);\n}\n\n/* MD5 finalization. Ends an MD5 message-_digest operation, writing the\nthe message _digest and zeroizing the context.\n*/\nvoid MD5::final() {\n    byte bits[8];\n    uint32 oldState[4];\n    uint32 oldCount[2];\n    uint32 index, padLen;\n\n    /* Save current state and count. */\n    memcpy(oldState, _state, 16);\n    memcpy(oldCount, _count, 8);\n\n    /* Save number of bits */\n    encode(_count, bits, 8);\n\n    /* Pad out to 56 mod 64. */\n    index = (uint32)((_count[0] >> 3) & 0x3f);\n    padLen = (index < 56) ? (56 - index) : (120 - index);\n    update(PADDING, padLen);\n\n    /* Append length (before padding) */\n    update(bits, 8);\n\n    /* Store state in digest */\n    encode(_state, _digest, 16);\n\n    /* Restore current state and count. */\n    memcpy(_state, oldState, 16);\n    memcpy(_count, oldCount, 8);\n}\n\n/* MD5 basic transformation. Transforms _state based on block. */\nvoid MD5::transform(const byte block[64]) {\n\n    uint32 a = _state[0], b = _state[1], c = _state[2], d = _state[3], x[16];\n\n    decode(block, x, 64);\n\n    /* Round 1 */\n    FF (a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */\n    FF (d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */\n    FF (c, d, a, b, x[2], S13, 0x242070db); /* 3 */\n    FF (b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */\n    FF (a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */\n    FF (d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */\n    FF (c, d, a, b, x[6], S13, 0xa8304613); /* 7 */\n    FF (b, c, d, a, x[7], S14, 0xfd469501); /* 8 */\n    FF (a, b, c, d, x[8], S11, 0x698098d8); /* 9 */\n    FF (d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */\n    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */\n    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */\n    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */\n    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */\n    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */\n    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */\n\n    /* Round 2 */\n    GG (a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */\n    GG (d, a, b, c, x[6], S22, 0xc040b340); /* 18 */\n    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */\n    GG (b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */\n    GG (a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */\n    GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */\n    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */\n    GG (b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */\n    GG (a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */\n    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */\n    GG (c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */\n    GG (b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */\n    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */\n    GG (d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */\n    GG (c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */\n    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */\n\n    /* Round 3 */\n    HH (a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */\n    HH (d, a, b, c, x[8], S32, 0x8771f681); /* 34 */\n    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */\n    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */\n    HH (a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */\n    HH (d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */\n    HH (c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */\n    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */\n    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */\n    HH (d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */\n    HH (c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */\n    HH (b, c, d, a, x[6], S34, 0x4881d05); /* 44 */\n    HH (a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */\n    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */\n    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */\n    HH (b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */\n\n    /* Round 4 */\n    II (a, b, c, d, x[0], S41, 0xf4292244); /* 49 */\n    II (d, a, b, c, x[7], S42, 0x432aff97); /* 50 */\n    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */\n    II (b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */\n    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */\n    II (d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */\n    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */\n    II (b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */\n    II (a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */\n    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */\n    II (c, d, a, b, x[6], S43, 0xa3014314); /* 59 */\n    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */\n    II (a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */\n    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */\n    II (c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */\n    II (b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */\n\n    _state[0] += a;\n    _state[1] += b;\n    _state[2] += c;\n    _state[3] += d;\n}\n\n/* Encodes input (ulong) into output (byte). Assumes length is\na multiple of 4.\n*/\nvoid MD5::encode(const uint32 *input, byte *output, size_t length) {\n\n    for (size_t i = 0, j = 0; j < length; ++i, j += 4) {\n        output[j] = (byte)(input[i] & 0xff);\n        output[j + 1] = (byte)((input[i] >> 8) & 0xff);\n        output[j + 2] = (byte)((input[i] >> 16) & 0xff);\n        output[j + 3] = (byte)((input[i] >> 24) & 0xff);\n    }\n}\n\n/* Decodes input (byte) into output (ulong). Assumes length is\na multiple of 4.\n*/\nvoid MD5::decode(const byte *input, uint32 *output, size_t length) {\n    for (size_t i = 0, j = 0; j < length; ++i, j += 4) {\n        output[i] = ((uint32) input[j]) | (((uint32) input[j + 1]) << 8) |\n                    (((uint32) input[j + 2]) << 16) | (((uint32) input[j + 3]) << 24);\n    }\n}\n\n/* Convert byte array to hex string. */\nNacosString MD5::bytesToHexString(const byte *input, size_t length) {\n    NacosString str;\n    str.reserve(length << 1);\n    for (size_t i = 0; i < length; ++i) {\n        int t = input[i];\n        int a = t / 16;\n        int b = t % 16;\n        str.append(1, HEX[a]);\n        str.append(1, HEX[b]);\n    }\n    return str;\n}\n\n/* Convert digest to string value */\nNacosString MD5::toString() {\n    return bytesToHexString(digest(), 16);\n}\n}//namespace nacos"
  },
  {
    "path": "src/crypto/md5/md5.h",
    "content": "#ifndef MD5_H\n#define MD5_H\n\n#include <string>\n#include <string.h>\n#include <fstream>\n#include \"NacosString.h\"\n\nnamespace nacos{\n/* Type define */\ntypedef unsigned char byte;\ntypedef unsigned int uint32;\n\nusing std::string;\nusing std::ifstream;\n\n/* MD5 declaration. */\nclass MD5 {\npublic:\n    MD5();\n\n    MD5(const void *input, size_t length);\n\n    MD5(const NacosString &str);\n\n    MD5(ifstream &in);\n\n    void update(const void *input, size_t length);\n\n    void update(const NacosString &str);\n\n    void update(ifstream &in);\n\n    const byte *digest();\n\n    NacosString toString();\n\n    void reset();\n\nprivate:\n    void update(const byte *input, size_t length);\n\n    void final();\n\n    void transform(const byte block[64]);\n\n    void encode(const uint32 *input, byte *output, size_t length);\n\n    void decode(const byte *input, uint32 *output, size_t length);\n\n    NacosString bytesToHexString(const byte *input, size_t length);\n\n    /* class uncopyable */\n    MD5(const MD5 &);\n\n    MD5 &operator=(const MD5 &);\n\nprivate:\n    uint32 _state[4]; /* state (ABCD) */\n    uint32 _count[2]; /* number of bits, modulo 2^64 (low-order word first) */\n    byte _buffer[64]; /* input buffer */\n    byte _digest[16]; /* message digest */\n    bool _finished;   /* calculate finished ? */\n\n    static const byte PADDING[64]; /* padding for calculate */\n    static const char HEX[16];\n    enum {\n        BUFFER_SIZE = 1024\n    };\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/debug/DebugAssertion.h",
    "content": "#ifndef __DEBUG_ASSERTION_H_\n#define __DEBUG_ASSERTION_H_\n\n#include <stdlib.h>\n#include <stdio.h>\n#include \"NacosString.h\"\n\nnamespace nacos{\n#define TEST_ITEM_START {\n#define TEST_ITEM(testName, testfn) {(testName), (testfn)},\n#define TEST_ITEM_END };\n\n#define NACOS_ASSERT(x) \\\nif (!(x)) \\\n{ \\\n    printf(\"Assertion failed! file:\" __FILE__\":%d\\n\", __LINE__); \\\n    abort(); \\\n}\n\ntypedef bool (*TESTFN)();\n\ntypedef struct tagTestData {\n    NacosString testName;\n    TESTFN testFn;\n} TestData;\n\n#define SHOULD_BE_TRUE(assertion, message) \\\ndo \\\n{ \\\n    if (!(assertion)) \\\n    { \\\n        cout << (message) << \"...:failed\" << endl; \\\n        return false; \\\n    } \\\n    cout << (message) << \"...:passed\" << endl; \\\n} while(0);\n\n#define SHOULD_BE_FALSE(assertion, message) SHOULD_BE_TRUE(!(assertion), (message))\n\n#ifdef NACOS_AUTH\n#define ADD_AUTH_INFO(x) \\\ndo { \\\n    (x)[\"nacos.auth.username\"] = \"nacos\"; \\\n    (x)[\"nacos.auth.password\"] = \"nacos\"; \\\n} while (0)\n#else\n#define ADD_AUTH_INFO(x)\n#endif\n\n#ifdef NACOS_SPAS\n#define ADD_SPAS_INFO(x) \\\ndo { \\\n    (x)[\"secretKey\"] = \"nacos\"; \\\n    (x)[\"accessKey\"] = \"nacos\"; \\\n} while (0)\n#else\n#define ADD_SPAS_INFO(x)\n#endif\n\n}//namespace nacos\n#endif"
  },
  {
    "path": "src/factory/NacosFactoryFactory.cpp",
    "content": "#include \"factory/NacosFactoryFactory.h\"\n#include \"src/factory/NacosServiceFactory.h\"\nnamespace nacos {\n\nINacosServiceFactory *NacosFactoryFactory::getNacosFactory(const NacosString &_configFile) {\n        NacosServiceFactory *factory = new NacosServiceFactory(_configFile);\n        return factory;\n}\n\nINacosServiceFactory *NacosFactoryFactory::getNacosFactory(Properties &_props) {\n        NacosServiceFactory *factory = new NacosServiceFactory(_props);\n        return factory;\n}\n\n}"
  },
  {
    "path": "src/factory/NacosServiceFactory.cpp",
    "content": "//\n// Created by liuhanyu on 2020/8/30.\n//\n\n#include \"src/factory/NacosServiceFactory.h\"\n#include \"src/init/Init.h\"\n#include \"src/naming/NacosNamingService.h\"\n#include \"src/naming/NacosNamingMaintainService.h\"\n#include \"ObjectConfigData.h\"\n#include \"src/config/NacosConfigService.h\"\n#include \"src/config/AppConfigManager.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/http/delegate/NoOpHttpDelegate.h\"\n#include \"src/http/delegate/NacosAuthHttpDelegate.h\"\n#include \"src/http/HTTPCli.h\"\n#include \"src/naming/subscribe/EventDispatcher.h\"\n#include \"src/naming/subscribe/SubscriptionPoller.h\"\n#include \"src/naming/subscribe/UdpNamingServiceListener.h\"\n#include \"src/naming/subscribe/HostReactor.h\"\n#include \"src/security/SecurityManager.h\"\n#include \"src/utils/ConfigParserUtils.h\"\n#include \"src/utils/SequenceProvider.h\"\n#include \"src/config/ConfigProxy.h\"\n#include \"src/utils/DirUtils.h\"\n\n//Unlike Java, in cpp, there's no container, no spring to do the ORM job, so I have to handle it myself\nnamespace nacos{\n\nvolatile bool NacosServiceFactory::logSystemInitialized = false;\n\nvoid buildSecurityManagerAndHttpDelegate(ObjectConfigData *objectConfigData) {\n    AppConfigManager *appConfigManager = objectConfigData->_appConfigManager;\n    if (appConfigManager->nacosAuthEnabled()) {\n        //nacos authentication is enabled\n        SecurityManager *securityManager = new SecurityManager(objectConfigData);\n        objectConfigData->_securityManager = securityManager;\n        HttpDelegate *httpDelegate = new NacosAuthHttpDelegate(objectConfigData);\n        objectConfigData->_httpDelegate = httpDelegate;\n    } else {\n        HttpDelegate *httpDelegate = new NoOpHttpDelegate(objectConfigData);\n        objectConfigData->_httpDelegate = httpDelegate;\n    }\n}\n\nAppConfigManager *NacosServiceFactory::buildConfigManager(ObjectConfigData *objectConfigData) {\n    //Create configuration data and load configs\n    AppConfigManager *appConfigManager = NULL;\n\n    if (configIsSet) {\n        appConfigManager = new AppConfigManager(configFile);\n        appConfigManager->loadConfig(configFile);\n    } else {\n        appConfigManager = new AppConfigManager(props);\n    }\n    objectConfigData->_appConfigManager = appConfigManager;\n\n    return appConfigManager;\n}\n\nvoid NacosServiceFactory::initializeRuntimeLogSettings(AppConfigManager *_appConfigManager) {\n    if (logSystemInitialized) {\n        return;\n    }\n\n    {\n        LockGuard __lockLogSystem(logSysInitLock);\n\n        if (logSystemInitialized) {\n            return;\n        }\n\n        logSystemInitialized = true;\n        Properties copiedProps = _appConfigManager->getAllConfig();\n        Logger::applyLogSettings(copiedProps);\n    }\n}\n\n//FIXME:Memory leak at initializing stage, e.g.:\n//when a HttpDelegate is allocated in CreateConfigService, after that an EXCEPTION is thrown during the initialization of ServerListManager\n//the resource for HttpDelegate is never released\nNamingService *NacosServiceFactory::CreateNamingService() NACOS_THROW(NacosException) {\n    Init::doInit();\n    checkConfig();\n    ObjectConfigData *objectConfigData = new ObjectConfigData(NAMING);\n    objectConfigData->name = \"config\";\n    objectConfigData->encoding = \"UTF-8\";\n\n    AppConfigManager *appConfigManager = buildConfigManager(objectConfigData);\n    initializeRuntimeLogSettings(appConfigManager);\n\n    //Create http client\n    IHttpCli *httpCli= new HTTPCli();\n    objectConfigData->_httpCli = httpCli;\n\n    buildSecurityManagerAndHttpDelegate(objectConfigData);\n\n    //Create server manager\n    ServerListManager *serverListManager = new ServerListManager(objectConfigData);\n    objectConfigData->_serverListManager = serverListManager;\n\n    //Create naming service & heartbeat sender\n    NamingProxy *namingProxy = new NamingProxy(objectConfigData);\n    objectConfigData->_serverProxy = namingProxy;\n    BeatReactor *beatReactor = new BeatReactor(objectConfigData);\n    objectConfigData->_beatReactor = beatReactor;\n\n    EventDispatcher *eventDispatcher = new EventDispatcher();\n    objectConfigData->_eventDispatcher = eventDispatcher;\n\n    SubscriptionPoller *subscriptionPoller = new SubscriptionPoller(objectConfigData);\n    objectConfigData->_subscriptionPoller = subscriptionPoller;\n\n    UdpNamingServiceListener *udpNamingServiceListener = new UdpNamingServiceListener(objectConfigData);\n    objectConfigData->_udpNamingServiceListener = udpNamingServiceListener;\n\n    HostReactor *hostReactor = new HostReactor(objectConfigData);\n    objectConfigData->_hostReactor = hostReactor;\n\n    const NacosString &seqConfile = appConfigManager->get(PropertyKeyConst::INSTANCE_ID_SEQ_FILE);\n    SequenceProvider<int64_t> *sequenceProvider = new SequenceProvider<int64_t>(seqConfile, 1, 10);\n    objectConfigData->_sequenceProvider = sequenceProvider;\n\n    objectConfigData->checkAssembledObject();\n    NamingService *instance = new NacosNamingService(objectConfigData);\n\n    log_debug(\"Created config data: %s\", objectConfigData->name.c_str());\n    return instance;\n}\n\nConfigService *NacosServiceFactory::CreateConfigService() NACOS_THROW(NacosException) {\n    Init::doInit();\n    checkConfig();\n    ObjectConfigData *objectConfigData = new ObjectConfigData(CONFIG);\n    objectConfigData->name = \"name\";\n    objectConfigData->encoding = \"UTF-8\";\n\n    AppConfigManager *appConfigManager = buildConfigManager(objectConfigData);\n    initializeRuntimeLogSettings(appConfigManager);\n\n    //Create http client\n    IHttpCli *httpCli = NULL;\n    httpCli = new HTTPCli();\n    objectConfigData->_httpCli = httpCli;\n\n    buildSecurityManagerAndHttpDelegate(objectConfigData);\n\n    //Create server manager\n    ServerListManager *serverListManager = new ServerListManager(objectConfigData);\n    objectConfigData->_serverListManager = serverListManager;\n\n    ConfigProxy *configProxy = new ConfigProxy(objectConfigData);\n    objectConfigData->_configProxy = configProxy;\n\n    LocalSnapshotManager *localSnapshotManager = new LocalSnapshotManager(appConfigManager);\n    objectConfigData->_localSnapshotManager = localSnapshotManager;\n    ClientWorker *clientWorker = new ClientWorker(objectConfigData);\n    objectConfigData->_clientWorker = clientWorker;\n    objectConfigData->checkAssembledObject();\n\n    ConfigService *instance = new NacosConfigService(objectConfigData);\n\n    log_debug(\"Created config data: %s\", objectConfigData->name.c_str());\n    return instance;\n}\n\nNamingMaintainService *NacosServiceFactory::CreateNamingMaintainService() NACOS_THROW(NacosException){\n    Init::doInit();\n    checkConfig();\n    ObjectConfigData *objectConfigData = new ObjectConfigData(MAINTAIN);\n    objectConfigData->name = \"config\";\n    objectConfigData->encoding = \"UTF-8\";\n\n    AppConfigManager *appConfigManager = buildConfigManager(objectConfigData);\n    initializeRuntimeLogSettings(appConfigManager);\n\n    //Create http client\n    IHttpCli *httpCli= new HTTPCli();\n    objectConfigData->_httpCli = httpCli;\n\n    buildSecurityManagerAndHttpDelegate(objectConfigData);\n\n    //Create server manager\n    ServerListManager *serverListManager = new ServerListManager(objectConfigData);\n    objectConfigData->_serverListManager = serverListManager;\n\n    //Create naming service & heartbeat sender\n    NamingProxy *namingProxy = new NamingProxy(objectConfigData);\n    objectConfigData->_serverProxy = namingProxy;\n\n    NacosNamingMaintainService *instance = new NacosNamingMaintainService(objectConfigData);\n\n    log_debug(\"Created config data: %s\", objectConfigData->name.c_str());\n    return instance;\n}\n\nNacosServiceFactory::~NacosServiceFactory() {\n\n}\n\nvoid NacosServiceFactory::checkConfig() NACOS_THROW(InvalidFactoryConfigException) {\n    if (!configIsSet && !propsIsSet) {\n        throw InvalidFactoryConfigException();\n    }\n}\n\nvoid NacosServiceFactory::setConfig(const NacosString &_configFile) {\n    configIsSet = true;\n    configFile = _configFile;\n};\n\nvoid NacosServiceFactory::setProps(Properties &_props) {\n    propsIsSet = true;\n    props = _props;\n};\n\nNacosServiceFactory::NacosServiceFactory() {\n    configIsSet = false;\n    propsIsSet = false;\n\n    setConfig(DirUtils::getCwd() + \"/\" + ConfigConstant::DEFAULT_CONFIG_FILE);\n}\n\nNacosServiceFactory::NacosServiceFactory(const NacosString &_configFile) {\n    configIsSet = false;\n    propsIsSet = false;\n    setConfig(_configFile);\n}\n\nNacosServiceFactory::NacosServiceFactory(Properties &_props) {\n    configIsSet = false;\n    propsIsSet = false;\n    setProps(_props);\n}\n\n}//namespace nacos"
  },
  {
    "path": "src/factory/NacosServiceFactory.h",
    "content": "//\n// Created by liuhanyu on 2020/8/30.\n//\n\n#ifndef NACOS_SDK_CPP_NACOSSERVICEFACTORY_H\n#define NACOS_SDK_CPP_NACOSSERVICEFACTORY_H\n\n#include \"factory/INacosServiceFactory.h\"\n#include \"Compatibility.h\"\n#include \"src/thread/Mutex.h\"\n\nnamespace nacos{\n\nclass AppConfigManager;\nclass ObjectConfigData;\n\nclass NacosServiceFactory : public INacosServiceFactory {\nprivate:\n    NacosString configFile;\n    Properties props;\n    bool configIsSet;\n    bool propsIsSet;\n\n    Mutex logSysInitLock;\n    static volatile bool logSystemInitialized;\n    void initializeRuntimeLogSettings(AppConfigManager *_appConfigManager);\n\n    void checkConfig() NACOS_THROW(InvalidFactoryConfigException);\n    AppConfigManager *buildConfigManager(ObjectConfigData *objectConfigData);\n\npublic:\n    void setConfig(const NacosString &_configFile);\n\n    void setProps(Properties &_props);\n\n    virtual NamingService *CreateNamingService() NACOS_THROW(NacosException);\n\n    virtual ConfigService *CreateConfigService() NACOS_THROW(NacosException);\n\n    virtual NamingMaintainService *CreateNamingMaintainService() NACOS_THROW(NacosException);\n\n    NacosServiceFactory();\n\n    NacosServiceFactory(const NacosString &_configFile);\n\n    NacosServiceFactory(Properties &_props);\n\n    virtual ~NacosServiceFactory();\n};\n\n}//namespace nacos\n\n#endif //NACOS_SDK_CPP_NACOSSERVICEFACTORY_H\n"
  },
  {
    "path": "src/factory/ObjectConfigData.cpp",
    "content": "#include \"ObjectConfigData.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/naming/NamingProxy.h\"\n#include \"src/naming/beat/BeatReactor.h\"\n#include \"src/naming/subscribe/EventDispatcher.h\"\n#include \"src/naming/subscribe/SubscriptionPoller.h\"\n#include \"src/naming/subscribe/UdpNamingServiceListener.h\"\n#include \"src/naming/subscribe/HostReactor.h\"\n#include \"src/listen/ClientWorker.h\"\n#include \"src/security/SecurityManager.h\"\n#include \"src/utils/UuidUtils.h\"\n#include \"src/utils/SequenceProvider.h\"\n#include \"src/config/ConfigProxy.h\"\n#include \"src/debug/DebugAssertion.h\"\n\nnamespace nacos{\n\nObjectConfigData::ObjectConfigData(FactoryType theFactoryType) {\n    objectId = UuidUtils::generateUuid();\n    factoryType = theFactoryType;\n    _httpDelegate = NULL;\n    _httpCli = NULL;\n    _serverProxy = NULL;\n    _beatReactor = NULL;\n    _eventDispatcher = NULL;\n    _subscriptionPoller = NULL;\n    _appConfigManager = NULL;\n    _serverListManager = NULL;\n    _clientWorker = NULL;\n    _localSnapshotManager = NULL;\n    _securityManager = NULL;\n    _configProxy = NULL;\n}\n\nvoid ObjectConfigData::checkNamingService() NACOS_THROW(NacosException) {\n    if (factoryType != NAMING) {\n        throw NacosException(NacosException::INVALID_PARAM, \"Invalid configuration for naming service, please check\");\n    }\n\n    NACOS_ASSERT(_httpDelegate != NULL);\n    NACOS_ASSERT(_httpCli != NULL);\n    NACOS_ASSERT(_serverProxy != NULL);\n    NACOS_ASSERT(_beatReactor != NULL);\n    NACOS_ASSERT(_eventDispatcher != NULL);\n    NACOS_ASSERT(_subscriptionPoller != NULL);\n    NACOS_ASSERT(_hostReactor != NULL);\n    NACOS_ASSERT(_appConfigManager != NULL);\n    NACOS_ASSERT(_serverListManager != NULL);\n    NACOS_ASSERT(_udpNamingServiceListener != NULL);\n    NACOS_ASSERT(_udpNamingServiceListener != NULL);\n    NACOS_ASSERT(_sequenceProvider != NULL);\n}\n\nvoid ObjectConfigData::checkConfigService() NACOS_THROW(NacosException) {\n    if (factoryType != CONFIG) {\n        throw NacosException(NacosException::INVALID_PARAM, \"Invalid configuration for config service, please check\");\n    }\n\n    NACOS_ASSERT(_appConfigManager != NULL);\n    NACOS_ASSERT(_httpCli != NULL);\n    NACOS_ASSERT(_httpDelegate != NULL);\n    NACOS_ASSERT(_serverListManager != NULL);\n    NACOS_ASSERT(_clientWorker != NULL);\n    NACOS_ASSERT(_localSnapshotManager != NULL);\n    NACOS_ASSERT(_configProxy != NULL);\n}\n\nvoid ObjectConfigData::checkMaintainService() NACOS_THROW(NacosException) {\n    if (factoryType != MAINTAIN) {\n        throw NacosException(NacosException::INVALID_PARAM, \"Invalid configuration for maintain service, please check\");\n    }\n\n    NACOS_ASSERT(_serverProxy != NULL);\n    NACOS_ASSERT(_httpDelegate != NULL);\n    NACOS_ASSERT(_httpCli != NULL);\n    NACOS_ASSERT(_appConfigManager != NULL);\n    NACOS_ASSERT(_serverListManager != NULL);\n}\n\nvoid ObjectConfigData::destroyConfigService() {\n\n    if (_clientWorker != NULL) {\n        _clientWorker->stopListening();\n    }\n\n    if (_securityManager != NULL) {\n        _securityManager->stop();\n    }\n\n    if (_serverListManager) {\n        _serverListManager->stop();\n    }\n\n    if (_clientWorker != NULL) {\n        _clientWorker->stopListening();\n        delete _clientWorker;\n        _clientWorker = NULL;\n    }\n\n    if (_httpDelegate != NULL) {\n        delete _httpDelegate;\n        _httpDelegate = NULL;\n    }\n\n    if (_securityManager != NULL) {\n        delete _securityManager;\n        _securityManager = NULL;\n    }\n\n    if (_serverListManager != NULL) {\n        delete _serverListManager;\n        _serverListManager = NULL;\n    }\n\n    if (_httpCli != NULL) {\n        delete _httpCli;\n        _httpCli = NULL;\n    }\n\n    if (_appConfigManager != NULL) {\n        delete _appConfigManager;\n        _appConfigManager = NULL;\n    }\n\n    if (_configProxy != NULL) {\n        delete _configProxy;\n        _configProxy = NULL;\n    }\n}\n\nvoid ObjectConfigData::destroyNamingService() {\n\n    if (_beatReactor != NULL) {\n        _beatReactor->stop();\n    }\n\n    if (_subscriptionPoller != NULL) {\n        _subscriptionPoller->stop();\n    }\n\n    if (_udpNamingServiceListener != NULL) {\n        _udpNamingServiceListener->stop();\n    }\n\n    if (_eventDispatcher != NULL) {\n        _eventDispatcher->stop();\n    }\n\n    if (_securityManager != NULL) {\n        _securityManager->stop();\n    }\n\n    if (_serverListManager) {\n        _serverListManager->stop();\n    }\n\n    if (_httpDelegate != NULL) {\n        delete _httpDelegate;\n        _httpDelegate = NULL;\n    }\n\n    if (_beatReactor != NULL) {\n        delete _beatReactor;\n        _beatReactor = NULL;\n    }\n\n    if (_subscriptionPoller != NULL)\n    {\n        delete _subscriptionPoller;\n        _subscriptionPoller = NULL;\n    }\n\n    if (_udpNamingServiceListener != NULL)\n    {\n        delete _udpNamingServiceListener;\n        _udpNamingServiceListener = NULL;\n    }\n\n    if (_eventDispatcher != NULL)\n    {\n        delete _eventDispatcher;\n        _eventDispatcher = NULL;\n    }\n\n    if (_hostReactor != NULL) {\n        delete _hostReactor;\n        _hostReactor = NULL;\n    }\n\n    if (_serverProxy != NULL) {\n        delete _serverProxy;\n        _serverProxy = NULL;\n    }\n\n    if (_securityManager != NULL) {\n        delete _securityManager;\n        _securityManager = NULL;\n    }\n\n    if (_serverListManager != NULL) {\n        delete _serverListManager;\n        _serverListManager = NULL;\n    }\n\n    if (_httpDelegate != NULL) {\n        delete _httpDelegate;\n        _httpDelegate = NULL;\n    }\n\n    if (_httpCli != NULL) {\n        delete _httpCli;\n        _httpCli = NULL;\n    }\n\n    if (_appConfigManager != NULL)\n    {\n        delete _appConfigManager;\n        _appConfigManager = NULL;\n    }\n\n    if (_sequenceProvider != NULL)\n    {\n        delete _sequenceProvider;\n        _sequenceProvider = NULL;\n    }\n}\n\nvoid ObjectConfigData::destroyMaintainService() {\n    if (_serverListManager != NULL) {\n        _serverListManager->stop();\n    }\n\n    if (_securityManager != NULL) {\n        _securityManager->stop();\n    }\n\n    if (_serverProxy != NULL) {\n        delete _serverProxy;\n        _serverProxy = NULL;\n    }\n    if (_serverListManager != NULL) {\n        delete _serverListManager;\n        _serverListManager = NULL;\n    }\n    if (_appConfigManager != NULL) {\n        delete _appConfigManager;\n        _appConfigManager = NULL;\n    }\n    if (_securityManager != NULL) {\n        delete _securityManager;\n        _securityManager = NULL;\n    }\n    if (_httpDelegate != NULL) {\n        delete _httpDelegate;\n        _httpDelegate = NULL;\n    }\n    if (_httpCli != NULL) {\n        delete _httpCli;\n        _httpCli = NULL;\n    }\n}\n\nvoid ObjectConfigData::checkAssembledObject() NACOS_THROW(NacosException) {\n    switch (factoryType) {\n    case NAMING:\n        checkNamingService();\n        return;\n    case CONFIG:\n        checkConfigService();\n        return;\n    case MAINTAIN:\n        checkMaintainService();\n        break;\n    default:\n        abort();//never happens\n    }\n}\n\nObjectConfigData::~ObjectConfigData() {\n    switch (factoryType) {\n    case NAMING:\n        destroyNamingService();\n        return;\n    case CONFIG:\n        destroyConfigService();\n        return;\n    case MAINTAIN:\n        destroyMaintainService();\n        break;\n    default:\n        abort();//never happens\n    }\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/factory/ObjectConfigData.h",
    "content": "#ifndef __OBJ_CFG_DATA_H_\n#define __OBJ_CFG_DATA_H_\n\n#include \"naming/NamingService.h\"\n#include \"config/ConfigService.h\"\n#include \"NacosExceptions.h\"\n#include \"Compatibility.h\"\n#include <stdint.h>\n\nnamespace nacos{\nclass HttpDelegate;\nclass IHttpCli;\nclass NamingProxy;\nclass BeatReactor;\nclass EventDispatcher;\nclass SubscriptionPoller;\nclass AppConfigManager;\nclass ServerListManager;\nclass ClientWorker;\nclass LocalSnapshotManager;\nclass SecurityManager;\nclass UdpNamingServiceListener;\nclass HostReactor;\nclass ConfigProxy;\ntemplate <typename T>class SequenceProvider;\n\nenum FactoryType {\n    CONFIG = 0,\n    NAMING = 1,\n    MAINTAIN = 2\n};\n\nclass ObjectConfigData {\nprivate:\n    FactoryType factoryType;\n    void destroyConfigService();\n    void destroyNamingService();\n    void destroyMaintainService();\n    //These functions are designed to prevent coding problems\n    //(i.e.: forget to initialize HttpDelegate for a ConfigService) rather than run-time errors\n    void checkConfigService() NACOS_THROW(NacosException);\n    void checkNamingService() NACOS_THROW(NacosException);\n    void checkMaintainService() NACOS_THROW(NacosException);\n    NacosString objectId;\npublic:\n    const NacosString &getObjectId() const { return objectId; };\n    ObjectConfigData(FactoryType theFactoryType);\n    void checkAssembledObject() NACOS_THROW(NacosException);\n    ~ObjectConfigData();\n    NacosString name;\n    NacosString encoding;\n    HttpDelegate *_httpDelegate;\n    IHttpCli *_httpCli;\n    NamingProxy *_serverProxy;\n    BeatReactor *_beatReactor;\n    EventDispatcher *_eventDispatcher;\n    SubscriptionPoller *_subscriptionPoller;\n    AppConfigManager *_appConfigManager;\n    ServerListManager *_serverListManager;\n    ClientWorker *_clientWorker;\n    LocalSnapshotManager *_localSnapshotManager;\n    SecurityManager *_securityManager;\n    UdpNamingServiceListener *_udpNamingServiceListener;\n    HostReactor *_hostReactor;\n    SequenceProvider<int64_t> *_sequenceProvider;\n    ConfigProxy *_configProxy;\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/http/HTTPCli.cpp",
    "content": "#include <string.h>\r\n#include \"HTTPCli.h\"\r\n#include \"src/utils/url.h\"\r\n#include \"constant/UtilAndComs.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\nusing namespace std;\r\n\r\nnamespace nacos{\r\nstatic size_t\r\nreceiveResponseCallback(\r\n        void *contents,\r\n        size_t size,\r\n        size_t nmemb,\r\n        void *userp\r\n) {\r\n    size_t realsize = size * nmemb;\r\n    NacosString *strbuf = (NacosString *) userp;\r\n\r\n    strbuf->append((char *) contents, realsize);\r\n\r\n    return realsize;\r\n}\r\n\r\nstatic size_t receiveHeaderCallback(\r\n        void *contents,\r\n        size_t size,\r\n        size_t nmemb,\r\n        void *userp\r\n) {\r\n    char *content_s = (char *) contents;\r\n    //Parse the 'HeaderName: HeaderContent' format\r\n    char *pos = strchr(content_s, ':');\r\n    if (pos != NULL)//Skip status\r\n    {\r\n        std::map <NacosString, NacosString> *respheaders = (std::map <NacosString, NacosString> *) userp;\r\n        NacosString k = NacosString(content_s, pos - content_s);\r\n        NacosString v = NacosString(pos + 1);\r\n        (*respheaders)[k] = v;\r\n    }\r\n    size_t realsize = size * nmemb;\r\n\r\n    log_debug(\"[HTTPCli]-receivedHeaders: %s\", (char *) contents);\r\n\r\n    return realsize;\r\n}\r\n\r\nHTTPCli::HTTPCli() {\r\n    /* init the curl session */\r\n    pthread_key_create(&pthreadKey, HTTPCli::destroyCurlHandle);\r\n}\r\n\r\nCURL *HTTPCli::getCurlHandle() {\r\n    CURL *curlHandle = pthread_getspecific(pthreadKey);\r\n    if (curlHandle == NULL) {\r\n        curlHandle = curl_easy_init();\r\n        pthread_setspecific(pthreadKey, reinterpret_cast<void *>(curlHandle));\r\n    }\r\n    return curlHandle;\r\n}\r\n\r\nvoid HTTPCli::destroyCurlHandle(void *arg) {\r\n    CURL *curlHandle = reinterpret_cast<CURL *>(arg);\r\n    if (curlHandle != NULL) {\r\n        curl_easy_cleanup(curlHandle);\r\n        curlHandle = NULL;\r\n    }\r\n}\r\n\r\nvoid HTTPCli::HTTPBasicSettings(CURL *curlHandle) {\r\n    curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, UtilAndComs::VERSION.c_str());\r\n    curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, receiveResponseCallback);\r\n    curl_easy_setopt(curlHandle, CURLOPT_HEADERFUNCTION, receiveHeaderCallback);\r\n\r\n    curl_easy_setopt(curlHandle, CURLOPT_TCP_KEEPALIVE, 1L);\r\n\r\n    /* keep-alive idle time to 120 seconds */\r\n    curl_easy_setopt(curlHandle, CURLOPT_TCP_KEEPIDLE, 120L);\r\n\r\n    /* interval time between keep-alive probes: 60 seconds */\r\n    curl_easy_setopt(curlHandle, CURLOPT_TCP_KEEPINTVL, 60L);\r\n\r\n}\r\n\r\nNacosString HTTPCli::encodingParams(list <NacosString> &params) {\r\n    NacosString encodedParms = \"\";\r\n    for (list<NacosString>::iterator it = params.begin(); it != params.end(); it++) {\r\n        if (encodedParms.compare(\"\") != 0) {\r\n            encodedParms.append(\"&\");\r\n        }\r\n        encodedParms.append(urlencode(*it));\r\n        it++;\r\n        encodedParms.append(\"=\" + urlencode(*it));\r\n    }\r\n\r\n    return encodedParms;\r\n}\r\n\r\nNacosString HTTPCli::encodingParams(map <NacosString, NacosString> &params) {\r\n    NacosString encodedParms = \"\";\r\n    for (map<NacosString, NacosString>::iterator it = params.begin(); it != params.end(); it++) {\r\n        if (encodedParms.compare(\"\") != 0) {\r\n            encodedParms.append(\"&\");\r\n        }\r\n        encodedParms.append(it->first + \"=\" + it->second);\r\n    }\r\n\r\n    return encodedParms;\r\n}\r\n\r\nvoid HTTPCli::assembleHeaders(list <NacosString> &assembledHeaders, list <NacosString> &headers) {\r\n    for (list<NacosString>::iterator it = headers.begin(); it != headers.end(); it++) {\r\n        NacosString curHeader = \"\";\r\n        curHeader.append(*it);\r\n        curHeader += \": \";\r\n        it++;\r\n        curHeader.append(*it);\r\n        assembledHeaders.push_back(curHeader);\r\n    }\r\n}\r\n\r\nHttpResult HTTPCli::httpGet\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                list <NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpGetInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\nHttpResult HTTPCli::httpGet\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                map <NacosString, NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpGetInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\nHttpResult HTTPCli::httpGetInternal\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                const NacosString &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    CURL *curlHandle = getCurlHandle();\r\n    CURLcode curlres;\r\n\r\n    NacosString Url = path;\r\n\r\n    if (paramValues.compare(\"\") != 0) {\r\n        Url += \"?\" + paramValues;\r\n    }\r\n    log_debug(\"[HTTPCli]-Get:Assembled URL with parms:%s\\n\", Url.c_str());\r\n\r\n    /*Headers look like:\r\n        foo\r\n        bar\r\n        bax\r\n        lol\r\n    We convert it into sth like with assembleHeaders():\r\n        foo: bar\r\n        bax: lol\r\n    */\r\n    list <NacosString> assembledHeaders;\r\n    assembleHeaders(assembledHeaders, headers);\r\n\r\n    //clear-ups\r\n    curl_easy_reset(curlHandle);\r\n    /* specify URL to get */\r\n    curl_easy_setopt(curlHandle, CURLOPT_URL, Url.c_str());\r\n\r\n    //Setup common parameters\r\n    HTTPBasicSettings(curlHandle);\r\n    /* send all data to this function  */\r\n    NacosString strbuf = \"\";\r\n    /* we pass our 'strbuf' struct to the callback function */\r\n    curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *) &strbuf);\r\n\r\n    /* Get response headers from the response */\r\n    std::map <NacosString, NacosString> respheaders;\r\n    curl_easy_setopt(curlHandle, CURLOPT_HEADERDATA, (void *) &respheaders);\r\n\r\n    //TODO:Time out in a more precise way\r\n    curl_easy_setopt(curlHandle, CURLOPT_TIMEOUT, readTimeoutMs / 1000);\r\n\r\n    /*Add the request headers to the request*/\r\n    struct curl_slist *headerlist = NULL;\r\n\r\n    for (list<NacosString>::iterator it = assembledHeaders.begin(); it != assembledHeaders.end(); it++) {\r\n        headerlist = curl_slist_append(headerlist, it->c_str());\r\n    }\r\n\r\n    if (headerlist != NULL) {\r\n        curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headerlist);\r\n    }\r\n\r\n\r\n    /* get it! */\r\n    curlres = curl_easy_perform(curlHandle);\r\n\r\n    /*Since the headerlist is not needed anymore, free it to prevent mem leak*/\r\n    if (headerlist != NULL) {\r\n        curl_slist_free_all(headerlist);\r\n        headerlist = NULL;\r\n    }\r\n\r\n    if (curlres != CURLE_OK) {\r\n        log_error(\"[HTTPCli]-Get:curl_easy_perform() failed: %d - %s\\n\",\r\n                  curlres, curl_easy_strerror(curlres));\r\n        throw NetworkException(curlres, curl_easy_strerror(curlres));\r\n    }\r\n\r\n    long response_code;\r\n    curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &response_code);\r\n    HttpResult httpresp = HttpResult(response_code, strbuf, respheaders);\r\n    httpresp.curlcode = curlres;\r\n    log_debug(\"[HTTPCli]-Get:%lu bytes retrieved\\n\", (unsigned long) strbuf.length());\r\n    log_debug(\"[HTTPCli]-Get:content:%s\\n\", strbuf.c_str());\r\n    log_debug(\"[HTTPCli]-Get:resp-code:%d\\n\", response_code);\r\n\r\n    return httpresp;\r\n}\r\n\r\n/*httpPost, post data are passed in list form like this:\r\n\tfoo\r\n\tbar\r\n\tbax\r\n\tlol\r\nWe convert it into sth like this:\r\n\tfoo=bar&bax=lol\r\n*/\r\nHttpResult HTTPCli::httpPost\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                list <NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpPostInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\n//httpPost, post data are passed in map form\r\nHttpResult HTTPCli::httpPost\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                map <NacosString, NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpPostInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\n//Implement of httpPost\r\nHttpResult HTTPCli::httpPostInternal\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                const NacosString &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    CURL *curlHandle = getCurlHandle();\r\n    CURLcode curlres;\r\n\r\n    NacosString Url = path;\r\n    log_debug(\"[HTTPCli]-POST:Assembled URL with parms:%s\\n\", Url.c_str());\r\n\r\n    /*Headers look like:\r\n        foo\r\n        bar\r\n        bax\r\n        lol\r\n    We convert it into sth like with assembleHeaders():\r\n        foo: bar\r\n        bax: lol\r\n    */\r\n    list <NacosString> assembledHeaders;\r\n    assembleHeaders(assembledHeaders, headers);\r\n\r\n    log_debug(\"[HTTPCli]-POST:Post data:%s\\n\", paramValues.c_str());\r\n\r\n    //clear-ups\r\n    curl_easy_reset(curlHandle);\r\n    /* specify URL to get */\r\n    curl_easy_setopt(curlHandle, CURLOPT_URL, Url.c_str());\r\n\r\n    curl_easy_setopt(curlHandle, CURLOPT_CUSTOMREQUEST, \"POST\");\r\n    curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, paramValues.c_str());\r\n    curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDSIZE, paramValues.size());\r\n    //Setup common parameters\r\n    HTTPBasicSettings(curlHandle);\r\n\r\n    NacosString strbuf = \"\";\r\n    /* we pass our 'strbuf' struct to the callback function */\r\n    curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *) &strbuf);\r\n\r\n    /* Get response headers from the response */\r\n    std::map <NacosString, NacosString> respheaders;\r\n    curl_easy_setopt(curlHandle, CURLOPT_HEADERDATA, (void *) &respheaders);\r\n\r\n    //TODO:Time out in a more precise way\r\n    curl_easy_setopt(curlHandle, CURLOPT_TIMEOUT, readTimeoutMs / 1000);\r\n\r\n    /*Add the request headers to the request*/\r\n    struct curl_slist *headerlist = NULL;\r\n\r\n    for (list<NacosString>::iterator it = assembledHeaders.begin(); it != assembledHeaders.end(); it++) {\r\n        headerlist = curl_slist_append(headerlist, it->c_str());\r\n        log_debug(\"[HTTPCli]-POST:RequestHeaders:%s\\n\", it->c_str());\r\n    }\r\n\r\n    if (headerlist != NULL) {\r\n        curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headerlist);\r\n    }\r\n\r\n\r\n    /* get it! */\r\n    curlres = curl_easy_perform(curlHandle);\r\n\r\n    /*Since the headerlist is not needed anymore, free it to prevent mem leak*/\r\n    if (headerlist != NULL) {\r\n        curl_slist_free_all(headerlist);\r\n        headerlist = NULL;\r\n    }\r\n\r\n    if (curlres != CURLE_OK) {\r\n        log_error(\"[HTTPCli]-POST:curl_easy_perform() failed: %d - %s\\n\",\r\n                  curlres, curl_easy_strerror(curlres));\r\n        throw NetworkException(curlres, curl_easy_strerror(curlres));\r\n    }\r\n\r\n    long response_code;\r\n    curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &response_code);\r\n    HttpResult httpresp = HttpResult(response_code, strbuf, respheaders);\r\n    httpresp.curlcode = curlres;\r\n\r\n    log_debug(\"[HTTPCli]-POST:%lu bytes retrieved\\n\", (unsigned long) strbuf.length());\r\n    log_debug(\"[HTTPCli]-POST:content:%s\\n\", strbuf.c_str());\r\n    log_debug(\"[HTTPCli]-POST:resp-code:%d\\n\", response_code);\r\n\r\n    return httpresp;\r\n}\r\n\r\n/*httpPut, put data are passed in list form like this:\r\n\tfoo\r\n\tbar\r\n\tbax\r\n\tlol\r\nWe convert it into sth like this:\r\n\tfoo=bar&bax=lol\r\n*/\r\nHttpResult HTTPCli::httpPut\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                list <NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpPutInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\n//httpPut, post data are passed in map form\r\nHttpResult HTTPCli::httpPut\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                map <NacosString, NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpPutInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\n//Implement of httpPut\r\nHttpResult HTTPCli::httpPutInternal\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                const NacosString &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    CURL *curlHandle = getCurlHandle();\r\n    CURLcode curlres;\r\n\r\n    NacosString Url = path;\r\n    log_debug(\"[HTTPCli]-PUT:Assembled URL with parms:%s\\n\", Url.c_str());\r\n\r\n    /*Headers look like:\r\n        foo\r\n        bar\r\n        bax\r\n        lol\r\n    We convert it into sth like with assembleHeaders():\r\n        foo: bar\r\n        bax: lol\r\n    */\r\n    list <NacosString> assembledHeaders;\r\n    assembleHeaders(assembledHeaders, headers);\r\n\r\n    log_debug(\"[HTTPCli]-PUT:Put data:%s\\n\", paramValues.c_str());\r\n\r\n    //clear-ups\r\n    curl_easy_reset(curlHandle);\r\n    /* specify URL to get */\r\n    curl_easy_setopt(curlHandle, CURLOPT_URL, Url.c_str());\r\n\r\n    curl_easy_setopt(curlHandle, CURLOPT_CUSTOMREQUEST, \"PUT\");\r\n    curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, paramValues.c_str());\r\n    curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDSIZE, paramValues.size());\r\n    //Setup common parameters\r\n    HTTPBasicSettings(curlHandle);\r\n\r\n    NacosString strbuf = \"\";\r\n    /* we pass our 'strbuf' struct to the callback function */\r\n    curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *) &strbuf);\r\n\r\n    /* Get response headers from the response */\r\n    std::map <NacosString, NacosString> respheaders;\r\n    curl_easy_setopt(curlHandle, CURLOPT_HEADERDATA, (void *) &respheaders);\r\n\r\n    //TODO:Time out in a more precise way\r\n    curl_easy_setopt(curlHandle, CURLOPT_TIMEOUT, readTimeoutMs / 1000);\r\n\r\n    /*Add the request headers to the request*/\r\n    struct curl_slist *headerlist = NULL;\r\n\r\n    for (list<NacosString>::iterator it = assembledHeaders.begin(); it != assembledHeaders.end(); it++) {\r\n        headerlist = curl_slist_append(headerlist, it->c_str());\r\n        log_debug(\"[HTTPCli]-PUT:RequestHeaders:%s\\n\", it->c_str());\r\n    }\r\n\r\n    if (headerlist != NULL) {\r\n        curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headerlist);\r\n    }\r\n\r\n\r\n    /* get it! */\r\n    curlres = curl_easy_perform(curlHandle);\r\n\r\n    /*Since the headerlist is not needed anymore, free it to prevent mem leak*/\r\n    if (headerlist != NULL) {\r\n        curl_slist_free_all(headerlist);\r\n        headerlist = NULL;\r\n    }\r\n\r\n    if (curlres != CURLE_OK) {\r\n        log_error(\"[HTTPCli]-PUT:curl_easy_perform() failed: %d - %s\\n\",\r\n                  curlres, curl_easy_strerror(curlres));\r\n        throw NetworkException(curlres, curl_easy_strerror(curlres));\r\n    }\r\n\r\n    long response_code;\r\n    curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &response_code);\r\n    HttpResult httpresp = HttpResult(response_code, strbuf, respheaders);\r\n    httpresp.curlcode = curlres;\r\n\r\n    log_debug(\"[HTTPCli]-PUT:%lu bytes retrieved\\n\", (unsigned long) strbuf.length());\r\n    log_debug(\"[HTTPCli]-PUT:content:%s\\n\", strbuf.c_str());\r\n    log_debug(\"[HTTPCli]-PUT:resp-code:%d\\n\", response_code);\r\n\r\n    return httpresp;\r\n}\r\n\r\nHttpResult HTTPCli::httpDelete\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                list <NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpDeleteInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\nHttpResult HTTPCli::httpDelete\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                map <NacosString, NacosString> &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    NacosString parmVal;\r\n    parmVal = encodingParams(paramValues);\r\n    return httpDeleteInternal(path, headers, parmVal, encoding, readTimeoutMs);\r\n}\r\n\r\nHttpResult HTTPCli::httpDeleteInternal\r\n        (\r\n                const NacosString &path,\r\n                list <NacosString> &headers,\r\n                const NacosString &paramValues,\r\n                const NacosString &encoding,\r\n                long readTimeoutMs\r\n        ) NACOS_THROW(NetworkException) {\r\n    CURL *curlHandle = getCurlHandle();\r\n    CURLcode curlres;\r\n\r\n    NacosString Url = path;\r\n\r\n    Url += \"?\" + paramValues;\r\n    log_debug(\"[HTTPCli]-DELETE:Assembled URL with parms:%s\\n\", Url.c_str());\r\n\r\n    /*Headers look like:\r\n        foo\r\n        bar\r\n        bax\r\n        lol\r\n    We convert it into sth like with assembleHeaders():\r\n        foo: bar\r\n        bax: lol\r\n    */\r\n    list <NacosString> assembledHeaders;\r\n    assembleHeaders(assembledHeaders, headers);\r\n\r\n    //clear-ups\r\n    curl_easy_reset(curlHandle);\r\n    /* specify URL to get */\r\n    curl_easy_setopt(curlHandle, CURLOPT_URL, Url.c_str());\r\n\r\n    //Setup common parameters\r\n    HTTPBasicSettings(curlHandle);\r\n    /* Set to DELETE, since this is a delete request*/\r\n    curl_easy_setopt(curlHandle, CURLOPT_CUSTOMREQUEST, \"DELETE\");\r\n\r\n    NacosString strbuf = \"\";\r\n    /* we pass our 'strbuf' struct to the callback function */\r\n    curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *) &strbuf);\r\n\r\n    /* Get response headers from the response */\r\n    std::map <NacosString, NacosString> respheaders;\r\n    curl_easy_setopt(curlHandle, CURLOPT_HEADERDATA, (void *) &respheaders);\r\n\r\n    //TODO:Time out in a more precise way\r\n    curl_easy_setopt(curlHandle, CURLOPT_TIMEOUT, readTimeoutMs / 1000);\r\n\r\n    /*Add the request headers to the request*/\r\n    struct curl_slist *headerlist = NULL;\r\n\r\n    for (list<NacosString>::iterator it = assembledHeaders.begin(); it != assembledHeaders.end(); it++) {\r\n        headerlist = curl_slist_append(headerlist, it->c_str());\r\n    }\r\n\r\n    if (headerlist != NULL) {\r\n        curl_easy_setopt(curlHandle, CURLOPT_HTTPHEADER, headerlist);\r\n    }\r\n\r\n\r\n    /* get it! */\r\n    curlres = curl_easy_perform(curlHandle);\r\n\r\n    /*Since the headerlist is not needed anymore, free it to prevent mem leak*/\r\n    if (headerlist != NULL) {\r\n        curl_slist_free_all(headerlist);\r\n        headerlist = NULL;\r\n    }\r\n\r\n    if (curlres != CURLE_OK) {\r\n        log_error(\"[HTTPCli]-DELETE:curl_easy_perform() failed: %d - %s\\n\",\r\n                  curlres, curl_easy_strerror(curlres));\r\n        throw NetworkException(curlres, curl_easy_strerror(curlres));\r\n    }\r\n\r\n    long response_code;\r\n    curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &response_code);\r\n    HttpResult httpresp = HttpResult(response_code, strbuf, respheaders);\r\n    httpresp.curlcode = curlres;\r\n\r\n    log_debug(\"[HTTPCli]-DELETE:%lu bytes retrieved\\n\", (unsigned long) strbuf.length());\r\n    log_debug(\"[HTTPCli]-DELETE:content:%s\\n\", strbuf.c_str());\r\n    log_debug(\"[HTTPCli]-DELETE:resp-code:%d\\n\", response_code);\r\n\r\n    return httpresp;\r\n}\r\n\r\nHTTPCli::~HTTPCli() {\r\n    CURL *curlHandle = pthread_getspecific(pthreadKey);\r\n    if (curlHandle != NULL) {\r\n        curl_easy_cleanup(curlHandle);\r\n    }\r\n    pthread_key_delete(pthreadKey);\r\n}\r\n\r\nvoid HTTPCli::HTTP_GLOBAL_INIT() {\r\n    curl_global_init(CURL_GLOBAL_ALL);\r\n}\r\n\r\nvoid HTTPCli::HTTP_GLOBAL_DEINIT() {\r\n    curl_global_cleanup();\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/http/HTTPCli.h",
    "content": "#ifndef __HTTP_CLI_H_\n#define __HTTP_CLI_H_\n\n\n#include <pthread.h>\n#include <curl/curl.h>\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"IHttpCli.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\n\nclass HTTPCli : public IHttpCli {\nprivate:\n    //CURL *curlHandle;\n    pthread_key_t pthreadKey;\n\n    CURL *getCurlHandle();\n\n    static void destroyCurlHandle(void *arg);\n\n    HttpResult httpGetInternal\n            (\n                    const NacosString &path,\n                    std::list <NacosString> &headers,\n                    const NacosString &paramValues,\n                    const NacosString &encoding,\n                    long readTimeoutMs\n            ) NACOS_THROW(NetworkException);\n\n    HttpResult httpPostInternal\n            (\n                    const NacosString &path,\n                    std::list <NacosString> &headers,\n                    const NacosString &paramValues,\n                    const NacosString &encoding,\n                    long readTimeoutMs\n            ) NACOS_THROW(NetworkException);\n\n    HttpResult httpPutInternal\n            (\n                    const NacosString &path,\n                    std::list <NacosString> &headers,\n                    const NacosString &paramValues,\n                    const NacosString &encoding,\n                    long readTimeoutMs\n            ) NACOS_THROW(NetworkException);\n\n    HttpResult httpDeleteInternal\n            (\n                    const NacosString &path,\n                    std::list <NacosString> &headers,\n                    const NacosString &paramValues,\n                    const NacosString &encoding,\n                    long readTimeoutMs\n            ) NACOS_THROW(NetworkException);\n\npublic:\n    static NacosString encodingParams(std::list <NacosString> &params);\n\n    static NacosString encodingParams(std::map <NacosString, NacosString> &params);\n\n    static void assembleHeaders(std::list <NacosString> &assembledHeaders, std::list <NacosString> &headers);\n\n    static void HTTPBasicSettings(CURL *curlHandle);\n\n    static void HTTP_GLOBAL_INIT();\n\n    static void HTTP_GLOBAL_DEINIT();\n\n    HTTPCli();\n\n    ~HTTPCli();\n\n    HttpResult httpGet(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpGet(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpDelete(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpDelete(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpPost(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpPost(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpPut(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n    HttpResult httpPut(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException);\n\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/http/HttpDelegate.h",
    "content": "#ifndef __HTTP_AGENT_H_\n#define __HTTP_AGENT_H_\n\n#include \"NacosExceptions.h\"\n#include \"NacosString.h\"\n#include \"IHttpCli.h\"\n#include \"Compatibility.h\"\n\n/**\n * HttpDelegate\n *\n * @author Liu, Hanyu\n */\nnamespace nacos{\nclass HttpDelegate {\nprotected:\n    HttpDelegate *_next;\npublic:\n    HttpDelegate() { _next = NULL; };\n\n    /**\n    * invoke http get method\n    * @param path http path\n    * @param headers http headers\n    * @param paramValues http paramValues http\n    * @param encoding http encode\n    * @param readTimeoutMs http timeout\n    * @return HttpResult http response\n    * @throws NetworkException If an input or output exception occurred\n    */\n\n    virtual HttpResult\n    httpGet(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n            const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException) = 0;\n\n    /**\n    * invoke http put method\n    * @param path http path\n    * @param headers http headers\n    * @param paramValues http paramValues http\n    * @param encoding http encode\n    * @param readTimeoutMs http timeout\n    * @return HttpResult http response\n    * @throws NetworkException If an input or output exception occurred\n    */\n    virtual HttpResult\n    httpPut(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n            const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException) = 0;\n\n    /**\n    * invoke http post method\n    * @param path http path\n    * @param headers http headers\n    * @param paramValues http paramValues http\n    * @param encoding http encode\n    * @param readTimeoutMs http timeout\n    * @return HttpResult http response\n    * @throws NetworkException If an input or output exception occurred\n    */\n    virtual HttpResult\n    httpPost(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n             const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException) = 0;\n\n    /**\n    * invoke http delete method\n    * @param path http path\n    * @param headers http headers\n    * @param paramValues http paramValues http\n    * @param encoding http encode\n    * @param readTimeoutMs http timeout\n    * @return HttpResult http response\n    * @throws NetworkException If an input or output exception occurred\n    */\n    virtual HttpResult\n    httpDelete(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n               const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException) = 0;\n\n    /**\n    * get encode\n    * @return NacosString\n    */\n    virtual NacosString getEncode() const = 0;\n\n    virtual ~HttpDelegate() {};\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/http/HttpStatus.h",
    "content": "#ifndef __HTTP_STATUS_H_\n#define __HTTP_STATUS_H_\n//Copied from JAVA source code HttpURLConnection.java\n// REMIND: do we want all these??\n// Others not here that we do want??\n\nclass HttpStatus\n{\npublic:\n/* 2XX: generally \"OK\" */\n\n/**\n * HTTP Status-Code 200: OK.\n */\nstatic const int HTTP_OK = 200;\n\n/**\n * HTTP Status-Code 201: Created.\n */\nstatic const int HTTP_CREATED = 201;\n\n/**\n * HTTP Status-Code 202: Accepted.\n */\nstatic const int HTTP_ACCEPTED = 202;\n\n/**\n * HTTP Status-Code 203: Non-Authoritative Information.\n */\nstatic const int HTTP_NOT_AUTHORITATIVE = 203;\n\n/**\n * HTTP Status-Code 204: No Content.\n */\nstatic const int HTTP_NO_CONTENT = 204;\n\n/**\n * HTTP Status-Code 205: Reset Content.\n */\nstatic const int HTTP_RESET = 205;\n\n/**\n * HTTP Status-Code 206: Partial Content.\n */\nstatic const int HTTP_PARTIAL = 206;\n\n/* 3XX: relocation/redirect */\n\n/**\n * HTTP Status-Code 300: Multiple Choices.\n */\nstatic const int HTTP_MULT_CHOICE = 300;\n\n/**\n * HTTP Status-Code 301: Moved Permanently.\n */\nstatic const int HTTP_MOVED_PERM = 301;\n\n/**\n * HTTP Status-Code 302: Temporary Redirect.\n */\nstatic const int HTTP_MOVED_TEMP = 302;\n\n/**\n * HTTP Status-Code 303: See Other.\n */\nstatic const int HTTP_SEE_OTHER = 303;\n\n/**\n * HTTP Status-Code 304: Not Modified.\n */\nstatic const int HTTP_NOT_MODIFIED = 304;\n\n/**\n * HTTP Status-Code 305: Use Proxy.\n */\nstatic const int HTTP_USE_PROXY = 305;\n\n/* 4XX: client error */\n\n/**\n * HTTP Status-Code 400: Bad Request.\n */\nstatic const int HTTP_BAD_REQUEST = 400;\n\n/**\n * HTTP Status-Code 401: Unauthorized.\n */\nstatic const int HTTP_UNAUTHORIZED = 401;\n\n/**\n * HTTP Status-Code 402: Payment Required.\n */\nstatic const int HTTP_PAYMENT_REQUIRED = 402;\n\n/**\n * HTTP Status-Code 403: Forbidden.\n */\nstatic const int HTTP_FORBIDDEN = 403;\n\n/**\n * HTTP Status-Code 404: Not Found.\n */\nstatic const int HTTP_NOT_FOUND = 404;\n\n/**\n * HTTP Status-Code 405: Method Not Allowed.\n */\nstatic const int HTTP_BAD_METHOD = 405;\n\n/**\n * HTTP Status-Code 406: Not Acceptable.\n */\nstatic const int HTTP_NOT_ACCEPTABLE = 406;\n\n/**\n * HTTP Status-Code 407: Proxy Authentication Required.\n */\nstatic const int HTTP_PROXY_AUTH = 407;\n\n/**\n * HTTP Status-Code 408: Request Time-Out.\n */\nstatic const int HTTP_CLIENT_TIMEOUT = 408;\n\n/**\n * HTTP Status-Code 409: Conflict.\n */\nstatic const int HTTP_CONFLICT = 409;\n\n/**\n * HTTP Status-Code 410: Gone.\n */\nstatic const int HTTP_GONE = 410;\n\n/**\n * HTTP Status-Code 411: Length Required.\n */\nstatic const int HTTP_LENGTH_REQUIRED = 411;\n\n/**\n * HTTP Status-Code 412: Precondition Failed.\n */\nstatic const int HTTP_PRECON_FAILED = 412;\n\n/**\n * HTTP Status-Code 413: Request Entity Too Large.\n */\nstatic const int HTTP_ENTITY_TOO_LARGE = 413;\n\n/**\n * HTTP Status-Code 414: Request-URI Too Large.\n */\nstatic const int HTTP_REQ_TOO_LONG = 414;\n\n/**\n * HTTP Status-Code 415: Unsupported Media Type.\n */\nstatic const int HTTP_UNSUPPORTED_TYPE = 415;\n\n/* 5XX: server error */\n\n/**\n * HTTP Status-Code 500: Internal Server Error.\n * @deprecated   it is misplaced and shouldn't have existed.\n */\nstatic const int HTTP_SERVER_ERROR = 500;\n\n/**\n * HTTP Status-Code 500: Internal Server Error.\n */\nstatic const int HTTP_INTERNAL_ERROR = 500;\n\n/**\n * HTTP Status-Code 501: Not Implemented.\n */\nstatic const int HTTP_NOT_IMPLEMENTED = 501;\n\n/**\n * HTTP Status-Code 502: Bad Gateway.\n */\nstatic const int HTTP_BAD_GATEWAY = 502;\n\n/**\n * HTTP Status-Code 503: Service Unavailable.\n */\nstatic const int HTTP_UNAVAILABLE = 503;\n\n/**\n * HTTP Status-Code 504: Gateway Timeout.\n */\nstatic const int HTTP_GATEWAY_TIMEOUT = 504;\n\n/**\n * HTTP Status-Code 505: HTTP Version Not Supported.\n */\nstatic const int HTTP_VERSION = 505;\n\n};\n#endif"
  },
  {
    "path": "src/http/IHttpCli.h",
    "content": "#ifndef __IHTTP_CLI_H_\n#define __IHTTP_CLI_H_\n\n#include <list>\n#include <map>\n#include <curl/curl.h>\n#include \"NacosExceptions.h\"\n#include \"NacosString.h\"\n#include \"Compatibility.h\"\n\n/**\n * HttpDelegate\n *\n * @author Liu, Hanyu\n */\nnamespace nacos{\nclass HttpResult {\npublic:\n    long code;\n    NacosString content;\n    std::map <NacosString, NacosString> headers;\n    CURLcode curlcode;\n\n    HttpResult(long _code, const NacosString &_content, std::map <NacosString, NacosString> &_headers)\n            : code(_code), content(_content) {\n        headers.insert(_headers.begin(), _headers.end());\n    }\n\n    HttpResult(long _code, const NacosString &_content) : code(_code), content(_content) {}\n\n    HttpResult() {\n        code = -1;\n        content = \"\";\n        headers.clear();\n    }\n\n    HttpResult operator=(HttpResult asignee) {\n        if (this != &asignee) {\n            headers.insert(asignee.headers.begin(), asignee.headers.end());\n            code = asignee.code;\n            content = asignee.content;\n            curlcode = asignee.curlcode;\n        }\n\n        return *this;\n    }\n};\n\nclass IHttpCli {\npublic:\n    static const int GET = 0;\n    static const int PUT = 1;\n    static const int POST = 3;\n    static const int DELETE = 4;\n\n    virtual HttpResult httpGet(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpGet(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpDelete(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpDelete(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpPost(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpPost(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpPut(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::list <NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual HttpResult httpPut(\n            const NacosString &path,\n            std::list <NacosString> &headers,\n            std::map <NacosString, NacosString> &paramValues,\n            const NacosString &encoding,\n            long readTimeoutMs\n    ) NACOS_THROW(NetworkException) = 0;\n\n    virtual ~IHttpCli() {};\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/http/delegate/NacosAuthHttpDelegate.cpp",
    "content": "//\n// Created by liuhanyu on 2020/12/5.\n//\n\n#include \"NacosAuthHttpDelegate.h\"\n#include \"src/security/SecurityManager.h\"\n\nusing namespace std;\n\nnamespace nacos {\nNacosString NacosAuthHttpDelegate::getEncode() const {\n    return encoding;\n}\n\nNacosAuthHttpDelegate::NacosAuthHttpDelegate(ObjectConfigData *objectConfigData) {\n    _objectConfigData = objectConfigData;\n}\n\nHttpResult NacosAuthHttpDelegate::httpGet\n(\n    const NacosString &path,\n    std::list<NacosString> &headers,\n    std::list<NacosString> &paramValues,\n    const NacosString &_encoding,\n    long readTimeoutMs\n) NACOS_THROW(NetworkException) {\n    HttpResult res;\n    _objectConfigData->_securityManager->addAccessToken2Req(paramValues);\n    res = _objectConfigData->_httpCli->httpGet(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\nHttpResult NacosAuthHttpDelegate::httpDelete\n(\n    const NacosString &path,\n    std::list<NacosString> &headers,\n    std::list<NacosString> &paramValues,\n    const NacosString &_encoding,\n    long readTimeoutMs\n) NACOS_THROW(NetworkException) {\n    HttpResult res;\n    _objectConfigData->_securityManager->addAccessToken2Req(paramValues);\n    res = _objectConfigData->_httpCli->httpDelete(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\nHttpResult NacosAuthHttpDelegate::httpPost\n(\n    const NacosString &path,\n    std::list<NacosString> &headers,\n    std::list<NacosString> &paramValues,\n    const NacosString &_encoding,\n    long readTimeoutMs\n) NACOS_THROW(NetworkException) {\n    HttpResult res;\n    _objectConfigData->_securityManager->addAccessToken2Req(paramValues);\n    res = _objectConfigData->_httpCli->httpPost(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\nHttpResult NacosAuthHttpDelegate::httpPut\n(\n    const NacosString &path,\n    std::list<NacosString> &headers,\n    std::list<NacosString> &paramValues,\n    const NacosString &_encoding,\n    long readTimeoutMs\n) NACOS_THROW(NetworkException) {\n    HttpResult res;\n    _objectConfigData->_securityManager->addAccessToken2Req(paramValues);\n    res = _objectConfigData->_httpCli->httpPut(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n}"
  },
  {
    "path": "src/http/delegate/NacosAuthHttpDelegate.h",
    "content": "//\n// Created by liuhanyu on 2020/12/5.\n//\n\n#ifndef NACOS_SDK_CPP_NACOSAUTHHTTPDELEGATE_H\n#define NACOS_SDK_CPP_NACOSAUTHHTTPDELEGATE_H\n\n#include \"NacosExceptions.h\"\n#include \"NacosString.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\n/**\n * NoOpHttpDelegate\n *\n * @author Liu, Hanyu\n * Send a request to the server with authentication header\n */\nnamespace nacos{\n    class NacosAuthHttpDelegate : public HttpDelegate {\n    private:\n        ObjectConfigData *_objectConfigData;\n        NacosString encoding;\n    public:\n        NacosAuthHttpDelegate(ObjectConfigData *objectConfigData);\n\n        HttpResult httpGet(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                           const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n        HttpResult httpPost(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                            const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n        virtual HttpResult\n        httpPut(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n        HttpResult\n        httpDelete(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                   const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n        NacosString getEncode() const;\n\n        virtual ~NacosAuthHttpDelegate() {\n        };\n    };\n}//namespace nacos\n\n#endif //NACOS_SDK_CPP_NACOSAUTHHTTPDELEGATE_H\n"
  },
  {
    "path": "src/http/delegate/NoOpHttpDelegate.cpp",
    "content": "#include \"NoOpHttpDelegate.h\"\n\nusing namespace std;\n\nnamespace nacos{\nNacosString NoOpHttpDelegate::getEncode() const {\n    return encoding;\n}\n\nNoOpHttpDelegate::NoOpHttpDelegate\n(\n    ObjectConfigData *objectConfigData\n) {\n    _objectConfigData = objectConfigData;\n}\n\nHttpResult NoOpHttpDelegate::httpGet\n        (\n                const NacosString &path,\n                std::list <NacosString> &headers,\n                std::list <NacosString> &paramValues,\n                const NacosString &_encoding,\n                long readTimeoutMs\n        ) NACOS_THROW(NetworkException) {\n    HttpResult res;\n\n    res = _objectConfigData->_httpCli->httpGet(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\nHttpResult NoOpHttpDelegate::httpDelete\n        (\n                const NacosString &path,\n                std::list <NacosString> &headers,\n                std::list <NacosString> &paramValues,\n                const NacosString &_encoding,\n                long readTimeoutMs\n        ) NACOS_THROW(NetworkException) {\n    HttpResult res;\n    res = _objectConfigData->_httpCli->httpDelete(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\nHttpResult NoOpHttpDelegate::httpPost\n        (\n                const NacosString &path,\n                std::list <NacosString> &headers,\n                std::list <NacosString> &paramValues,\n                const NacosString &_encoding,\n                long readTimeoutMs\n        ) NACOS_THROW(NetworkException) {\n    HttpResult res;\n\n    res = _objectConfigData->_httpCli->httpPost(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\nHttpResult NoOpHttpDelegate::httpPut\n        (\n                const NacosString &path,\n                std::list <NacosString> &headers,\n                std::list <NacosString> &paramValues,\n                const NacosString &_encoding,\n                long readTimeoutMs\n        ) NACOS_THROW(NetworkException) {\n\n    HttpResult res;\n    res = _objectConfigData->_httpCli->httpPut(path, headers, paramValues, _encoding, readTimeoutMs);\n    return res;\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/http/delegate/NoOpHttpDelegate.h",
    "content": "#ifndef __SVR_HTTP_AGENT_H_\n#define __SVR_HTTP_AGENT_H_\n\n#include \"NacosExceptions.h\"\n#include \"NacosString.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\n/**\n * NoOpHttpDelegate\n *\n * @author Liu, Hanyu\n * Directly send request to HttpCli without any operation\n */\nnamespace nacos{\nclass NoOpHttpDelegate : public HttpDelegate {\nprivate:\n    ObjectConfigData *_objectConfigData;\n    NacosString encoding;\npublic:\n    NoOpHttpDelegate(ObjectConfigData *objectConfigData);\n\n    HttpResult httpGet(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                       const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n    HttpResult httpPost(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n                        const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n    virtual HttpResult\n    httpPut(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n            const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n    HttpResult\n    httpDelete(const NacosString &path, std::list <NacosString> &headers, std::list <NacosString> &paramValues,\n               const NacosString &encoding, long readTimeoutMs) NACOS_THROW(NetworkException);\n\n    NacosString getEncode() const;\n\n    virtual ~NoOpHttpDelegate() {\n    };\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/init/Init.cpp",
    "content": "#include \"Init.h\"\n#include \"src/http/HTTPCli.h\"\n#include \"src/config/SnapShotSwitch.h\"\n#include \"src/config/JVMUtil.h\"\n#include \"naming/ServiceInfo2.h\"\n#include \"constant/UtilAndComs.h\"\n#include \"src/utils/UuidUtils.h\"\n#include \"src/utils/RandomUtils.h\"\n#include \"src/thread/Thread.h\"\n#include \"src/crypto/MACProvider.h\"\nstatic nacos::Init initobj;//Implicitly call the constructors\n\nnamespace nacos{\nMutex Init::initflagMutex;\nbool Init::inited = false;\nbool SnapShotSwitch::isSnapShot = true;\nbool JVMUtil::_isMultiInstance = false;\nServiceInfo2 ServiceInfo2::nullServiceInfo2;\n\nvoid Init::doInit() {\n    if (inited) {\n        return;\n    }\n    {\n        LockGuard _initGuard(initflagMutex);\n        if (inited) {\n            return;\n        }\n\n        Logger::Init();\n        MACProvider::Init();\n        HTTPCli::HTTP_GLOBAL_INIT();\n        UtilAndComs::Init();\n        RandomUtils::Init();\n        UuidUtils::Init();\n        Thread::Init();\n        ServiceInfo2::nullServiceInfo2.setNull(true);\n        inited = true;\n    }\n}\n\nvoid Init::doDeinit() {\n    if (!inited) {\n        return;\n    }\n\n    {\n        LockGuard _initGuard(initflagMutex);\n        if (!inited) {\n            return;\n        }\n\n        MACProvider::DeInit();\n        Thread::DeInit();\n        UuidUtils::DeInit();\n        RandomUtils::DeInit();\n        HTTPCli::HTTP_GLOBAL_DEINIT();\n        Logger::deInit();\n        inited = false;\n    }\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/init/Init.h",
    "content": "#ifndef __INIT_H_\n#define __INIT_H_\n\n#include \"src/thread/Mutex.h\"\n\nnamespace nacos{\nclass Init {\nprivate:\n    static bool inited;\n    static Mutex initflagMutex;\npublic:\n    Init() {};\n\n    ~Init() { doDeinit(); };\n\n    static void doInit();\n\n    static void doDeinit();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/json/JSON.cpp",
    "content": "#include \"src/json/JSON.h\"\n#include \"src/naming/beat/BeatInfo.h\"\n#include \"NacosString.h\"\n\n/**\n * JSON\n *\n * @author Liu, Hanyu\n * Adapter from nacos-cpp-cli to a json parser\n */\nusing namespace std;\nusing namespace rapidjson;\nusing nacos::naming::Selector;\n\nnamespace nacos{\nNacosString documentToString(const Document &d) {\n    StringBuffer buffer;\n    Writer <StringBuffer> writer(buffer);\n    d.Accept(writer);\n    NacosString result = buffer.GetString();\n    return result;\n}\n\nNacosString valueToString(const Value &d) {\n    StringBuffer buffer;\n    Writer <StringBuffer> writer(buffer);\n    d.Accept(writer);\n    NacosString result = buffer.GetString();\n    return result;\n}\n\nNacosString JSON::toJSONString(const map <NacosString, NacosString> &mapinfo) {\n    Document d;\n    d.SetObject();\n    for (map<NacosString, NacosString>::const_iterator it = mapinfo.begin(); it != mapinfo.end(); it++) {\n        Value k;\n        k.SetString(it->first.c_str(), d.GetAllocator());\n        Value v;\n        v.SetString(it->second.c_str(), d.GetAllocator());\n        d.AddMember(k, v, d.GetAllocator());\n    }\n\n    return documentToString(d);\n}\n\nvoid JSON::Map2JSONObject(Document &d, Value &jsonOb, map <NacosString, NacosString> &mapinfo) {\n    jsonOb.SetObject();\n    for (map<NacosString, NacosString>::iterator it = mapinfo.begin(); it != mapinfo.end(); it++) {\n        Value k;\n        k.SetString(it->first.c_str(), d.GetAllocator());\n        Value v;\n        v.SetString(it->second.c_str(), d.GetAllocator());\n        jsonOb.AddMember(k, v, d.GetAllocator());\n    }\n}\n\nvoid JSON::JSONObject2Map(std::map <NacosString, NacosString> &mapinfo, const Value &jsonOb) {\n    for (Value::ConstMemberIterator iter = jsonOb.MemberBegin(); iter != jsonOb.MemberEnd(); ++iter) {\n        NacosString name = iter->name.GetString();\n        NacosString value = iter->value.GetString();\n        mapinfo[name] = value;\n    }\n}\n\n//Add key-value\nvoid AddKV(Document &d, const NacosString &k, const NacosString &v) {\n    Value k_, v_;\n    k_.SetString(k.c_str(), d.GetAllocator());\n    v_.SetString(v.c_str(), d.GetAllocator());\n    d.AddMember(k_, v_, d.GetAllocator());\n}\n\n//Add key-Object\nvoid AddKO(Document &d, const NacosString &k, Value &o) {\n    Value k_;\n    k_.SetString(k.c_str(), d.GetAllocator());\n    d.AddMember(k_, o, d.GetAllocator());\n}\n\nNacosString JSON::toJSONString(BeatInfo &beatInfo) {\n    Document d;\n    d.SetObject();\n    AddKV(d, \"port\", NacosStringOps::valueOf(beatInfo.port));\n    AddKV(d, \"ip\", beatInfo.ip);\n    AddKV(d, \"weight\", NacosStringOps::valueOf(beatInfo.weight));\n    AddKV(d, \"serviceName\", beatInfo.serviceName);\n    AddKV(d, \"cluster\", beatInfo.cluster);\n    AddKV(d, \"scheduled\", NacosStringOps::valueOf(beatInfo.scheduled));\n    Value metadata;\n    Map2JSONObject(d, metadata, beatInfo.metadata);\n    AddKO(d, \"metadata\", metadata);\n\n    //d[\"port\"] = NacosStringOps::valueOf(beatInfo.port);\n    //d[\"ip\"] = beatInfo.ip;\n    //d[\"weight\"] = NacosStringOps::valueOf(beatInfo.weight);\n    //d[\"serviceName\"] = beatInfo.serviceName;\n    //d[\"cluster\"] = beatInfo.cluster;\n    //d[\"scheduled\"] = beatInfo.scheduled;\n    //d[\"metadata\"] = toJSONString(beatInfo.metadata);\n    return documentToString(d);\n}\n\nlong JSON::getLong(const NacosString &jsonString, const NacosString &fieldname) {\n    Document d;\n    d.Parse(jsonString.c_str());\n    Value &s = d[fieldname.c_str()];\n    return s.GetInt64();\n}\n\nInstance JSON::Json2Instance(const Value &host) NACOS_THROW(NacosException) {\n    Instance theinstance;\n\n    if (host.HasMember(\"instanceId\")) {\n        const Value &instanceId = host[\"instanceId\"];\n        theinstance.instanceId = instanceId.GetString();\n    }\n\n    markRequired(host, \"port\");\n    const Value &port = host[\"port\"];\n    if (!port.IsInt()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing port for Instance!\");\n    }\n    theinstance.port = port.GetInt();\n\n    markRequired(host, \"ip\");\n    const Value &ip = host[\"ip\"];\n    theinstance.ip = ip.GetString();\n\n    markRequired(host, \"weight\");\n    const Value &weight = host[\"weight\"];\n    if (!weight.IsDouble()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing weight for Instance!\");\n    }\n    theinstance.weight = weight.GetDouble();\n\n    markRequired(host, \"metadata\");\n    const Value &metadata = host[\"metadata\"];\n\n    std::map <NacosString, NacosString> mtdata;\n    JSONObject2Map(mtdata, metadata);\n\n    theinstance.metadata = mtdata;\n\n    markRequired(host, \"healthy\");\n    const Value &healthy = host[\"healthy\"];\n    if (!healthy.IsBool()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing healthy for Instance!\");\n    }\n    theinstance.healthy = healthy.GetBool();\n\n    markRequired(host, \"enabled\");\n    const Value &enabled = host[\"enabled\"];\n    if (!enabled.IsBool()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing enabled for Instance!\");\n    }\n    theinstance.enabled = enabled.GetBool();\n\n    if (host.HasMember(\"clusterName\")) {\n        const Value &clusterName = host[\"clusterName\"];\n        theinstance.clusterName = clusterName.GetString();\n    }\n\n    return theinstance;\n}\n\nInstance JSON::Json2Instance(const NacosString &jsonString) NACOS_THROW(NacosException) {\n    Document d;\n    d.Parse(jsonString.c_str());\n\n    Instance theinstance;\n\n    markRequired(d, \"instanceId\");\n    const Value &instanceId = d[\"instanceId\"];\n    theinstance.instanceId = instanceId.GetString();\n\n    markRequired(d, \"port\");\n    const Value &port = d[\"port\"];\n    if (!port.IsInt()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing port for Instance!\");\n    }\n    theinstance.port = port.GetInt();\n\n    markRequired(d, \"ip\");\n    const Value &ip = d[\"ip\"];\n    theinstance.ip = ip.GetString();\n\n    markRequired(d, \"weight\");\n    const Value &weight = d[\"weight\"];\n    if (!weight.IsDouble()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing weight for Instance!\");\n    }\n    theinstance.weight = weight.GetDouble();\n\n    markRequired(d, \"metadata\");\n    const Value &metadata = d[\"metadata\"];\n\n    std::map <NacosString, NacosString> mtdata;\n    JSONObject2Map(mtdata, metadata);\n    theinstance.metadata = mtdata;\n\n    markRequired(d, \"healthy\");\n    const Value &healthy = d[\"healthy\"];\n    if (!healthy.IsBool()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing healthy for Instance!\");\n    }\n    theinstance.healthy = healthy.GetBool();\n\n    markRequired(d, \"service\");\n    const Value &service = d[\"service\"];\n    theinstance.serviceName = service.GetString();\n\n    markRequired(d, \"clusterName\");\n    const Value &clusterName = d[\"clusterName\"];\n    theinstance.clusterName = clusterName.GetString();\n\n    return theinstance;\n}\n\nvoid JSON::markRequired(const Document &d, const NacosString &requiredField) NACOS_THROW(NacosException) {\n    if (!d.HasMember(requiredField.c_str())) {\n        throw NacosException(NacosException::LACK_JSON_FIELD, \"Missing required field:\" + requiredField);\n    }\n}\n\nvoid JSON::markRequired(const Value &v, const NacosString &requiredField) NACOS_THROW(NacosException) {\n    if (!v.HasMember(requiredField.c_str())) {\n        throw NacosException(NacosException::LACK_JSON_FIELD, \"Missing required field:\" + requiredField);\n    }\n}\n\nServiceInfo JSON::JsonStr2ServiceInfo(const NacosString &jsonString) NACOS_THROW(NacosException) {\n    ServiceInfo si;\n    Document d;\n    d.Parse(jsonString.c_str());\n\n    if (d.HasParseError()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT,\n                             \"Error while parsing the JSON String for ServiceInfo!\");\n    }\n\n    //bugfix #75, need to refresh the lastRefTime if it is present in the json\n    if (d.HasMember(\"lastRefTime\")) {\n        const Value &lastRefTime = d[\"lastRefTime\"];\n        if (!lastRefTime.IsInt64()) {\n            throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing lastRefTime for ServiceInfo!\");\n        }\n        si.setLastRefTime(lastRefTime.GetInt64());\n    }\n\n    markRequired(d, \"name\");\n    const Value &name = d[\"name\"];\n    ServiceInfo::fromKey(si, name.GetString());\n\n    markRequired(d, \"clusters\");\n    const Value &clusters = d[\"clusters\"];\n    si.setClusters(clusters.GetString());\n\n    markRequired(d, \"cacheMillis\");\n    const Value &cacheMillis = d[\"cacheMillis\"];\n    if (!cacheMillis.IsInt64()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing cacheMillis for ServiceInfo!\");\n    }\n    si.setCacheMillis(cacheMillis.GetInt64());\n\n    markRequired(d, \"hosts\");\n    const Value &hosts = d[\"hosts\"];\n    if (hosts.Size() == 0) {\n        return si;\n    }\n\n    std::list <Instance> hostlist;\n    for (SizeType i = 0; i < hosts.Size(); i++) {\n        const Value &curhost = hosts[i];\n        Instance curinstance = Json2Instance(curhost);\n        hostlist.push_back(curinstance);\n    }\n\n    si.setHosts(hostlist);\n\n    markRequired(d, \"checksum\");\n    const Value &checkSum = d[\"checksum\"];\n    si.setChecksum(checkSum.GetString());\n\n    return si;\n}\n\nNacosServerInfo parseOneNacosSvr(const Value &curSvr) {\n    NacosServerInfo res;\n    res.setIp(curSvr[\"ip\"].GetString());\n    res.setPort(curSvr[\"servePort\"].GetInt());\n    res.setSite(curSvr[\"site\"].GetString());\n    res.setWeight(curSvr[\"weight\"].GetFloat());\n    res.setAdWeight(curSvr[\"adWeight\"].GetFloat());\n    res.setAlive(curSvr[\"alive\"].GetBool());\n    res.setLastRefTime(curSvr[\"lastRefTime\"].GetInt64());\n    if (!curSvr[\"lastRefTimeStr\"].IsNull()) {\n        res.setLastRefTimeStr(curSvr[\"lastRefTimeStr\"].GetString());\n    }\n    res.setKey(curSvr[\"key\"].GetString());\n    return res;\n}\n\nlist <NacosServerInfo> JSON::Json2NacosServerInfo(const NacosString &nacosString) NACOS_THROW(NacosException) {\n    list <NacosServerInfo> nacosServerList;\n    ServiceInfo si;\n    Document d;\n    d.Parse(nacosString.c_str());\n\n    if (d.HasParseError()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT,\n                             \"Error while parsing the JSON String for NacosServerInfo!\");\n    }\n\n    markRequired(d, \"servers\");\n    const Value &servers = d[\"servers\"];\n    if (!servers.IsArray()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing servers for NacosServerInfo!\");\n    }\n\n    for (SizeType i = 0; i < servers.Size(); i++) {\n        const Value &curSvr = servers[i];\n        NacosServerInfo curSvrInfo = parseOneNacosSvr(curSvr);\n        nacosServerList.push_back(curSvrInfo);\n    }\n\n    return nacosServerList;\n}\n\nListView<NacosString> JSON::Json2ServiceList(const NacosString &nacosString) NACOS_THROW(NacosException) {\n    ListView<NacosString> serviceList;\n    ServiceInfo si;\n    Document d;\n    d.Parse(nacosString.c_str());\n\n    if (d.HasParseError()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT,\n                             \"Error while parsing the JSON String for ServiceList!\");\n    }\n\n    markRequired(d, \"count\");\n    markRequired(d, \"doms\");\n    const Value &count = d[\"count\"];\n    if (!count.IsInt()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing servers for ServiceList.count!\");\n    }\n\n    serviceList.setCount(count.GetInt());\n\n    const Value &doms = d[\"doms\"];\n    if (!doms.IsArray()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing servers for ServiceList.doms!\");\n    }\n\n    list<NacosString> names;\n\n    for (SizeType i = 0; i < doms.Size(); i++) {\n        const Value &curName = doms[i];\n        names.push_back(curName.GetString());\n    }\n    serviceList.setData(names);\n\n    return serviceList;\n}\n\nmap<NacosString, NacosString> parseMetadata(const Value &value) {\n    map<NacosString, NacosString> metadata;\n\n    for (Value::ConstMemberIterator iter = value.MemberBegin();\n        iter != value.MemberEnd(); ++iter){\n        metadata[iter->name.GetString()] = iter->value.GetString();\n    }\n\n    return metadata;\n}\n\nServiceInfo2 JSON::Json2ServiceInfo2(const NacosString &nacosString) NACOS_THROW(NacosException) {\n    ServiceInfo2 serviceInfo2;\n    Document d;\n    d.Parse(nacosString.c_str());\n\n    markRequired(d, \"groupName\");\n    markRequired(d, \"namespaceId\");\n    markRequired(d, \"name\");\n    const Value &groupName = d[\"groupName\"];\n    const Value &namespaceId = d[\"namespaceId\"];\n    const Value &name = d[\"name\"];\n    serviceInfo2.setGroupName(groupName.GetString());\n    serviceInfo2.setNamespaceId(namespaceId.GetString());\n    serviceInfo2.setName(name.GetString());\n\n    const Value &selector = d[\"selector\"];\n\n    serviceInfo2.setSelector(valueToString(selector));\n\n    markRequired(d, \"protectThreshold\");\n    const Value &protectThreshold = d[\"protectThreshold\"];\n    serviceInfo2.setProtectThreshold(protectThreshold.GetDouble());\n\n    //service info metadata\n    const Value &serviceMetadata = d[\"metadata\"];\n    if (!serviceMetadata.IsObject()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing metadata for ServiceInfo2!\");\n    }\n\n    serviceInfo2.setMetadata(parseMetadata(serviceMetadata));\n\n    const Value &clusterlist = d[\"clusters\"];\n    if (!clusterlist.IsArray()) {\n        throw NacosException(NacosException::INVALID_JSON_FORMAT, \"Error while parsing clusters for ServiceInfo2.clusters!\");\n    }\n\n    //cluster metadata\n    for (SizeType i = 0; i < clusterlist.Size(); i++) {\n        const Value &curClusterJson = clusterlist[i];\n        Cluster curCluster;\n        curCluster.setName(curClusterJson[\"name\"].GetString());\n        curCluster.setMetadata(parseMetadata(curClusterJson[\"metadata\"]));\n        HealthChecker healthChecker;\n        curCluster.setHealthChecker(healthChecker);\n    }\n\n    return serviceInfo2;\n}\n\nAccessToken JSON::Json2AccessToken(const NacosString &nacosString) NACOS_THROW(NacosException)\n{\n    AccessToken accessTokenRes;\n    Document d;\n    d.Parse(nacosString.c_str());\n    markRequired(d, \"accessToken\");\n    const Value &accessToken = d[\"accessToken\"];\n    accessTokenRes.accessToken = accessToken.GetString();\n    markRequired(d, \"tokenTtl\");\n    const Value &tokenTtl = d[\"tokenTtl\"];\n    accessTokenRes.tokenTtl = tokenTtl.GetInt();\n    markRequired(d, \"globalAdmin\");\n    const Value &globalAdmin = d[\"globalAdmin\"];\n    accessTokenRes.globalAdmin = globalAdmin.GetBool();\n\n    return accessTokenRes;\n}\n\nPushPacket JSON::Json2PushPacket(const char *jsonString) NACOS_THROW(NacosException)\n{\n    PushPacket pushPacket;\n    Document d;\n    d.Parse(jsonString);\n    markRequired(d, \"data\");\n    const Value &data = d[\"data\"];\n    pushPacket.data = data.GetString();\n\n    markRequired(d, \"type\");\n    const Value &type = d[\"type\"];\n    pushPacket.type = type.GetString();\n\n    markRequired(d, \"lastRefTime\");\n    const Value &lastRefTime = d[\"lastRefTime\"];\n    pushPacket.lastRefTime = lastRefTime.GetInt64();\n\n    return pushPacket;\n}\n\n}//namespace nacos"
  },
  {
    "path": "src/json/JSON.h",
    "content": "#ifndef __JSON_H_\n#define __JSON_H_\n\n#include <map>\n#include \"NacosString.h\"\n#include \"src/naming/beat/BeatInfo.h\"\n#include \"naming/ServiceInfo.h\"\n#include \"src/json/rapidjson/document.h\"\n#include \"src/json/rapidjson/writer.h\"\n#include \"src/json/rapidjson/stringbuffer.h\"\n#include \"naming/Instance.h\"\n#include \"src/server/NacosServerInfo.h\"\n#include \"naming/ListView.h\"\n#include \"naming/ServiceInfo2.h\"\n#include \"src/security/SecurityManager.h\"\n#include \"src/naming/subscribe/UdpNamingServiceListener.h\"\n#include \"Compatibility.h\"\n\n/**\n * JSON\n *\n * @author Liu, Hanyu\n * Adapter from nacos-sdk-cpp to a json parser\n */\nnamespace nacos{\nclass JSON {\npublic:\n    static NacosString toJSONString(BeatInfo &beatInfo);\n\n    static NacosString toJSONString(const std::map <NacosString, NacosString> &mapinfo);\n\n    static void Map2JSONObject(rapidjson::Document &d, rapidjson::Value &jsonOb, std::map <NacosString, NacosString> &mapinfo);\n\n    static void JSONObject2Map(std::map <NacosString, NacosString> &mapinfo, const rapidjson::Value &jsonOb);\n\n    static long getLong(const NacosString &jsonString, const NacosString &fieldname);\n\n    static ServiceInfo JsonStr2ServiceInfo(const NacosString &jsonString) NACOS_THROW(NacosException);\n\n    static Instance Json2Instance(const rapidjson::Value &jsonString) NACOS_THROW(NacosException);\n\n    static Instance Json2Instance(const NacosString &jsonString) NACOS_THROW(NacosException);\n\n    static void markRequired(const rapidjson::Document &d, const NacosString &requiredField) NACOS_THROW(NacosException);\n\n    static void markRequired(const rapidjson::Value &d, const NacosString &requiredField) NACOS_THROW(NacosException);\n\n    static std::list<NacosServerInfo> Json2NacosServerInfo(const NacosString &nacosString) NACOS_THROW(NacosException);\n\n    static ServiceInfo2 Json2ServiceInfo2(const NacosString &nacosString) NACOS_THROW(NacosException);\n\n    static ListView<NacosString> Json2ServiceList(const NacosString &nacosString) NACOS_THROW(NacosException);\n\n    static AccessToken Json2AccessToken(const NacosString &nacosString) NACOS_THROW(NacosException);\n\n    static PushPacket Json2PushPacket(const char *jsonString) NACOS_THROW(NacosException);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/json/rapidjson/allocators.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ALLOCATORS_H_\n#define RAPIDJSON_ALLOCATORS_H_\n\n#include \"rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Allocator\n\n/*! \\class rapidjson::Allocator\n    \\brief Concept for allocating, resizing and freeing memory block.\n    \n    Note that Malloc() and Realloc() are non-static but Free() is static.\n    \n    So if an allocator need to support Free(), it needs to put its pointer in \n    the header of memory block.\n\n\\code\nconcept Allocator {\n    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().\n\n    // Allocate a memory block.\n    // \\param size of the memory block in bytes.\n    // \\returns pointer to the memory block.\n    void* Malloc(size_t size);\n\n    // Resize a memory block.\n    // \\param originalPtr The pointer to current memory block. Null pointer is permitted.\n    // \\param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)\n    // \\param newSize the new size in bytes.\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);\n\n    // Free a memory block.\n    // \\param pointer to the memory block. Null pointer is permitted.\n    static void Free(void *ptr);\n};\n\\endcode\n*/\n\n\n/*! \\def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-defined kDefaultChunkCapacity definition.\n\n    User can define this as any \\c size that is a power of 2.\n*/\n\n#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY\n#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CrtAllocator\n\n//! C-runtime library allocator.\n/*! This class is just wrapper for standard C library memory routines.\n    \\note implements Allocator concept\n*/\nclass CrtAllocator {\npublic:\n    static const bool kNeedFree = true;\n    void* Malloc(size_t size) { \n        if (size) //  behavior of malloc(0) is implementation defined.\n            return std::malloc(size);\n        else\n            return NULL; // standardize to returning NULL.\n    }\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n        (void)originalSize;\n        if (newSize == 0) {\n            std::free(originalPtr);\n            return NULL;\n        }\n        return std::realloc(originalPtr, newSize);\n    }\n    static void Free(void *ptr) { std::free(ptr); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// MemoryPoolAllocator\n\n//! Default memory allocator used by the parser and DOM.\n/*! This allocator allocate memory blocks from pre-allocated memory chunks. \n\n    It does not free memory blocks. And Realloc() only allocate new memory.\n\n    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.\n\n    User may also supply a buffer as the first chunk.\n\n    If the user-buffer is full then additional chunks are allocated by BaseAllocator.\n\n    The user-buffer is not deallocated by this allocator.\n\n    \\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.\n    \\note implements Allocator concept\n*/\ntemplate <typename BaseAllocator = CrtAllocator>\nclass MemoryPoolAllocator {\npublic:\n    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)\n\n    //! Constructor with chunkSize.\n    /*! \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n        \\param baseAllocator The allocator for allocating memory chunks.\n    */\n    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : \n        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n    {\n    }\n\n    //! Constructor with user-supplied buffer.\n    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.\n\n        The user buffer will not be deallocated when this allocator is destructed.\n\n        \\param buffer User supplied buffer.\n        \\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).\n        \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n        \\param baseAllocator The allocator for allocating memory chunks.\n    */\n    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :\n        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n    {\n        RAPIDJSON_ASSERT(buffer != 0);\n        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));\n        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);\n        chunkHead_->capacity = size - sizeof(ChunkHeader);\n        chunkHead_->size = 0;\n        chunkHead_->next = 0;\n    }\n\n    //! Destructor.\n    /*! This deallocates all memory chunks, excluding the user-supplied buffer.\n    */\n    ~MemoryPoolAllocator() {\n        Clear();\n        RAPIDJSON_DELETE(ownBaseAllocator_);\n    }\n\n    //! Deallocates all memory chunks, excluding the user-supplied buffer.\n    void Clear() {\n        while (chunkHead_ && chunkHead_ != userBuffer_) {\n            ChunkHeader* next = chunkHead_->next;\n            baseAllocator_->Free(chunkHead_);\n            chunkHead_ = next;\n        }\n        if (chunkHead_ && chunkHead_ == userBuffer_)\n            chunkHead_->size = 0; // Clear user buffer\n    }\n\n    //! Computes the total capacity of allocated memory chunks.\n    /*! \\return total capacity in bytes.\n    */\n    size_t Capacity() const {\n        size_t capacity = 0;\n        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n            capacity += c->capacity;\n        return capacity;\n    }\n\n    //! Computes the memory blocks allocated.\n    /*! \\return total used bytes.\n    */\n    size_t Size() const {\n        size_t size = 0;\n        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n            size += c->size;\n        return size;\n    }\n\n    //! Allocates a memory block. (concept Allocator)\n    void* Malloc(size_t size) {\n        if (!size)\n            return NULL;\n\n        size = RAPIDJSON_ALIGN(size);\n        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)\n            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))\n                return NULL;\n\n        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;\n        chunkHead_->size += size;\n        return buffer;\n    }\n\n    //! Resizes a memory block (concept Allocator)\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n        if (originalPtr == 0)\n            return Malloc(newSize);\n\n        if (newSize == 0)\n            return NULL;\n\n        originalSize = RAPIDJSON_ALIGN(originalSize);\n        newSize = RAPIDJSON_ALIGN(newSize);\n\n        // Do not shrink if new size is smaller than original\n        if (originalSize >= newSize)\n            return originalPtr;\n\n        // Simply expand it if it is the last allocation and there is sufficient space\n        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {\n            size_t increment = static_cast<size_t>(newSize - originalSize);\n            if (chunkHead_->size + increment <= chunkHead_->capacity) {\n                chunkHead_->size += increment;\n                return originalPtr;\n            }\n        }\n\n        // Realloc process: allocate and copy memory, do not free original buffer.\n        if (void* newBuffer = Malloc(newSize)) {\n            if (originalSize)\n                std::memcpy(newBuffer, originalPtr, originalSize);\n            return newBuffer;\n        }\n        else\n            return NULL;\n    }\n\n    //! Frees a memory block (concept Allocator)\n    static void Free(void *ptr) { (void)ptr; } // Do nothing\n\nprivate:\n    //! Copy constructor is not permitted.\n    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;\n    //! Copy assignment operator is not permitted.\n    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;\n\n    //! Creates a new chunk.\n    /*! \\param capacity Capacity of the chunk in bytes.\n        \\return true if success.\n    */\n    bool AddChunk(size_t capacity) {\n        if (!baseAllocator_)\n            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();\n        if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {\n            chunk->capacity = capacity;\n            chunk->size = 0;\n            chunk->next = chunkHead_;\n            chunkHead_ =  chunk;\n            return true;\n        }\n        else\n            return false;\n    }\n\n    static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.\n\n    //! Chunk header for perpending to each chunk.\n    /*! Chunks are stored as a singly linked list.\n    */\n    struct ChunkHeader {\n        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).\n        size_t size;        //!< Current size of allocated memory in bytes.\n        ChunkHeader *next;  //!< Next chunk in the linked list.\n    };\n\n    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.\n    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.\n    void *userBuffer_;          //!< User supplied buffer.\n    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.\n    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ENCODINGS_H_\n"
  },
  {
    "path": "src/json/rapidjson/cursorstreamwrapper.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_\n#define RAPIDJSON_CURSORSTREAMWRAPPER_H_\n\n#include \"stream.h\"\n\n#if defined(__GNUC__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#if defined(_MSC_VER) && _MSC_VER <= 1800\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\nRAPIDJSON_DIAG_OFF(4512)  // assignment operator could not be generated\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n\n//! Cursor stream wrapper for counting line and column number if error exists.\n/*!\n    \\tparam InputStream     Any stream that implements Stream Concept\n*/\ntemplate <typename InputStream, typename Encoding = UTF8<> >\nclass CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    CursorStreamWrapper(InputStream& is):\n        GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}\n\n    // counting line and column number\n    Ch Take() {\n        Ch ch = this->is_.Take();\n        if(ch == '\\n') {\n            line_ ++;\n            col_ = 0;\n        } else {\n            col_ ++;\n        }\n        return ch;\n    }\n\n    //! Get the error line number, if error exists.\n    size_t GetLine() const { return line_; }\n    //! Get the error column number, if error exists.\n    size_t GetColumn() const { return col_; }\n\nprivate:\n    size_t line_;   //!< Current Line\n    size_t col_;    //!< Current Column\n};\n\n#if defined(_MSC_VER) && _MSC_VER <= 1800\nRAPIDJSON_DIAG_POP\n#endif\n\n#if defined(__GNUC__)\nRAPIDJSON_DIAG_POP\n#endif\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_\n"
  },
  {
    "path": "src/json/rapidjson/document.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_DOCUMENT_H_\n#define RAPIDJSON_DOCUMENT_H_\n\n/*! \\file document.h */\n\n#include \"reader.h\"\n#include \"src/json/rapidjson/internal/meta.h\"\n#include \"src/json/rapidjson/internal/strfunc.h\"\n#include \"memorystream.h\"\n#include \"encodedstream.h\"\n#include <new>      // placement new\n#include <limits>\n\nRAPIDJSON_DIAG_PUSH\n#ifdef __clang__\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(switch-enum)\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_OFF(4127) // conditional expression is constant\nRAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_OFF(effc++)\n#endif // __GNUC__\n\n#ifndef RAPIDJSON_NOMEMBERITERATORCLASS\n#include <iterator> // std::random_access_iterator_tag\n#endif\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#include <utility> // std::move\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n// Forward declaration.\ntemplate <typename Encoding, typename Allocator>\nclass GenericValue;\n\ntemplate <typename Encoding, typename Allocator, typename StackAllocator>\nclass GenericDocument;\n\n//! Name-value pair in a JSON object value.\n/*!\n    This class was internal to GenericValue. It used to be a inner struct.\n    But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.\n    https://code.google.com/p/rapidjson/issues/detail?id=64\n*/\ntemplate <typename Encoding, typename Allocator> \nstruct GenericMember { \n    GenericValue<Encoding, Allocator> name;     //!< name of member (must be a string)\n    GenericValue<Encoding, Allocator> value;    //!< value of member.\n\n    // swap() for std::sort() and other potential use in STL.\n    friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT {\n        a.name.Swap(b.name);\n        a.value.Swap(b.value);\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericMemberIterator\n\n#ifndef RAPIDJSON_NOMEMBERITERATORCLASS\n\n//! (Constant) member iterator for a JSON object value\n/*!\n    \\tparam Const Is this a constant iterator?\n    \\tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)\n    \\tparam Allocator   Allocator type for allocating memory of object, array and string.\n\n    This class implements a Random Access Iterator for GenericMember elements\n    of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].\n\n    \\note This iterator implementation is mainly intended to avoid implicit\n        conversions from iterator values to \\c NULL,\n        e.g. from GenericValue::FindMember.\n\n    \\note Define \\c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a\n        pointer-based implementation, if your platform doesn't provide\n        the C++ <iterator> header.\n\n    \\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator\n */\ntemplate <bool Const, typename Encoding, typename Allocator>\nclass GenericMemberIterator {\n\n    friend class GenericValue<Encoding,Allocator>;\n    template <bool, typename, typename> friend class GenericMemberIterator;\n\n    typedef GenericMember<Encoding,Allocator> PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n\npublic:\n    //! Iterator type itself\n    typedef GenericMemberIterator Iterator;\n    //! Constant iterator type\n    typedef GenericMemberIterator<true,Encoding,Allocator>  ConstIterator;\n    //! Non-constant iterator type\n    typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;\n\n    /** \\name std::iterator_traits support */\n    //@{\n    typedef ValueType      value_type;\n    typedef ValueType *    pointer;\n    typedef ValueType &    reference;\n    typedef std::ptrdiff_t difference_type;\n    typedef std::random_access_iterator_tag iterator_category;\n    //@}\n\n    //! Pointer to (const) GenericMember\n    typedef pointer         Pointer;\n    //! Reference to (const) GenericMember\n    typedef reference       Reference;\n    //! Signed integer type (e.g. \\c ptrdiff_t)\n    typedef difference_type DifferenceType;\n\n    //! Default constructor (singular value)\n    /*! Creates an iterator pointing to no element.\n        \\note All operations, except for comparisons, are undefined on such values.\n     */\n    GenericMemberIterator() : ptr_() {}\n\n    //! Iterator conversions to more const\n    /*!\n        \\param it (Non-const) iterator to copy from\n\n        Allows the creation of an iterator from another GenericMemberIterator\n        that is \"less const\".  Especially, creating a non-constant iterator\n        from a constant iterator are disabled:\n        \\li const -> non-const (not ok)\n        \\li const -> const (ok)\n        \\li non-const -> const (ok)\n        \\li non-const -> non-const (ok)\n\n        \\note If the \\c Const template parameter is already \\c false, this\n            constructor effectively defines a regular copy-constructor.\n            Otherwise, the copy constructor is implicitly defined.\n    */\n    GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}\n    Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }\n\n    //! @name stepping\n    //@{\n    Iterator& operator++(){ ++ptr_; return *this; }\n    Iterator& operator--(){ --ptr_; return *this; }\n    Iterator  operator++(int){ Iterator old(*this); ++ptr_; return old; }\n    Iterator  operator--(int){ Iterator old(*this); --ptr_; return old; }\n    //@}\n\n    //! @name increment/decrement\n    //@{\n    Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }\n    Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }\n\n    Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }\n    Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }\n    //@}\n\n    //! @name relations\n    //@{\n    bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }\n    bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }\n    bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }\n    bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }\n    bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }\n    bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }\n    //@}\n\n    //! @name dereference\n    //@{\n    Reference operator*() const { return *ptr_; }\n    Pointer   operator->() const { return ptr_; }\n    Reference operator[](DifferenceType n) const { return ptr_[n]; }\n    //@}\n\n    //! Distance\n    DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }\n\nprivate:\n    //! Internal constructor from plain pointer\n    explicit GenericMemberIterator(Pointer p) : ptr_(p) {}\n\n    Pointer ptr_; //!< raw pointer\n};\n\n#else // RAPIDJSON_NOMEMBERITERATORCLASS\n\n// class-based member iterator implementation disabled, use plain pointers\n\ntemplate <bool Const, typename Encoding, typename Allocator>\nclass GenericMemberIterator;\n\n//! non-const GenericMemberIterator\ntemplate <typename Encoding, typename Allocator>\nclass GenericMemberIterator<false,Encoding,Allocator> {\n    //! use plain pointer as iterator type\n    typedef GenericMember<Encoding,Allocator>* Iterator;\n};\n//! const GenericMemberIterator\ntemplate <typename Encoding, typename Allocator>\nclass GenericMemberIterator<true,Encoding,Allocator> {\n    //! use plain const pointer as iterator type\n    typedef const GenericMember<Encoding,Allocator>* Iterator;\n};\n\n#endif // RAPIDJSON_NOMEMBERITERATORCLASS\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericStringRef\n\n//! Reference to a constant string (not taking a copy)\n/*!\n    \\tparam CharType character type of the string\n\n    This helper class is used to automatically infer constant string\n    references for string literals, especially from \\c const \\b (!)\n    character arrays.\n\n    The main use is for creating JSON string values without copying the\n    source string via an \\ref Allocator.  This requires that the referenced\n    string pointers have a sufficient lifetime, which exceeds the lifetime\n    of the associated GenericValue.\n\n    \\b Example\n    \\code\n    Value v(\"foo\");   // ok, no need to copy & calculate length\n    const char foo[] = \"foo\";\n    v.SetString(foo); // ok\n\n    const char* bar = foo;\n    // Value x(bar); // not ok, can't rely on bar's lifetime\n    Value x(StringRef(bar)); // lifetime explicitly guaranteed by user\n    Value y(StringRef(bar, 3));  // ok, explicitly pass length\n    \\endcode\n\n    \\see StringRef, GenericValue::SetString\n*/\ntemplate<typename CharType>\nstruct GenericStringRef {\n    typedef CharType Ch; //!< character type of the string\n\n    //! Create string reference from \\c const character array\n#ifndef __clang__ // -Wdocumentation\n    /*!\n        This constructor implicitly creates a constant string reference from\n        a \\c const character array.  It has better performance than\n        \\ref StringRef(const CharType*) by inferring the string \\ref length\n        from the array length, and also supports strings containing null\n        characters.\n\n        \\tparam N length of the string, automatically inferred\n\n        \\param str Constant character array, lifetime assumed to be longer\n            than the use of the string in e.g. a GenericValue\n\n        \\post \\ref s == str\n\n        \\note Constant complexity.\n        \\note There is a hidden, private overload to disallow references to\n            non-const character arrays to be created via this constructor.\n            By this, e.g. function-scope arrays used to be filled via\n            \\c snprintf are excluded from consideration.\n            In such cases, the referenced string should be \\b copied to the\n            GenericValue instead.\n     */\n#endif\n    template<SizeType N>\n    GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT\n        : s(str), length(N-1) {}\n\n    //! Explicitly create string reference from \\c const character pointer\n#ifndef __clang__ // -Wdocumentation\n    /*!\n        This constructor can be used to \\b explicitly  create a reference to\n        a constant string pointer.\n\n        \\see StringRef(const CharType*)\n\n        \\param str Constant character pointer, lifetime assumed to be longer\n            than the use of the string in e.g. a GenericValue\n\n        \\post \\ref s == str\n\n        \\note There is a hidden, private overload to disallow references to\n            non-const character arrays to be created via this constructor.\n            By this, e.g. function-scope arrays used to be filled via\n            \\c snprintf are excluded from consideration.\n            In such cases, the referenced string should be \\b copied to the\n            GenericValue instead.\n     */\n#endif\n    explicit GenericStringRef(const CharType* str)\n        : s(str), length(NotNullStrLen(str)) {}\n\n    //! Create constant string reference from pointer and length\n#ifndef __clang__ // -Wdocumentation\n    /*! \\param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n        \\param len length of the string, excluding the trailing NULL terminator\n\n        \\post \\ref s == str && \\ref length == len\n        \\note Constant complexity.\n     */\n#endif\n    GenericStringRef(const CharType* str, SizeType len)\n        : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }\n\n    GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}\n\n    //! implicit conversion to plain CharType pointer\n    operator const Ch *() const { return s; }\n\n    const Ch* const s; //!< plain CharType pointer\n    const SizeType length; //!< length of the string (excluding the trailing NULL terminator)\n\nprivate:\n    SizeType NotNullStrLen(const CharType* str) {\n        RAPIDJSON_ASSERT(str != 0);\n        return internal::StrLen(str);\n    }\n\n    /// Empty string - used when passing in a NULL pointer\n    static const Ch emptyString[];\n\n    //! Disallow construction from non-const array\n    template<SizeType N>\n    GenericStringRef(CharType (&str)[N]) /* = delete */;\n    //! Copy assignment operator not permitted - immutable type\n    GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;\n};\n\ntemplate<typename CharType>\nconst CharType GenericStringRef<CharType>::emptyString[] = { CharType() };\n\n//! Mark a character pointer as constant string\n/*! Mark a plain character pointer as a \"string literal\".  This function\n    can be used to avoid copying a character string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n    \\tparam CharType Character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n\n    \\see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const CharType* str) {\n    return GenericStringRef<CharType>(str);\n}\n\n//! Mark a character pointer as constant string\n/*! Mark a plain character pointer as a \"string literal\".  This function\n    can be used to avoid copying a character string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n\n    This version has better performance with supplied length, and also\n    supports string containing null characters.\n\n    \\tparam CharType character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\param length The length of source string.\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {\n    return GenericStringRef<CharType>(str, SizeType(length));\n}\n\n#if RAPIDJSON_HAS_STDSTRING\n//! Mark a string object as constant string\n/*! Mark a string object (e.g. \\c std::string) as a \"string literal\".\n    This function can be used to avoid copying a string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n\n    \\tparam CharType character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n    \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {\n    return GenericStringRef<CharType>(str.data(), SizeType(str.size()));\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue type traits\nnamespace internal {\n\ntemplate <typename T, typename Encoding = void, typename Allocator = void>\nstruct IsGenericValueImpl : FalseType {};\n\n// select candidates according to nested encoding and allocator types\ntemplate <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>\n    : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};\n\n// helper to match arbitrary GenericValue instantiations, including derived classes\ntemplate <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// TypeHelper\n\nnamespace internal {\n\ntemplate <typename ValueType, typename T>\nstruct TypeHelper {};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, bool> {\n    static bool Is(const ValueType& v) { return v.IsBool(); }\n    static bool Get(const ValueType& v) { return v.GetBool(); }\n    static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }\n    static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, int> {\n    static bool Is(const ValueType& v) { return v.IsInt(); }\n    static int Get(const ValueType& v) { return v.GetInt(); }\n    static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }\n    static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, unsigned> {\n    static bool Is(const ValueType& v) { return v.IsUint(); }\n    static unsigned Get(const ValueType& v) { return v.GetUint(); }\n    static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }\n    static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }\n};\n\n#ifdef _MSC_VER\nRAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));\ntemplate<typename ValueType>\nstruct TypeHelper<ValueType, long> {\n    static bool Is(const ValueType& v) { return v.IsInt(); }\n    static long Get(const ValueType& v) { return v.GetInt(); }\n    static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }\n    static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }\n};\n\nRAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));\ntemplate<typename ValueType>\nstruct TypeHelper<ValueType, unsigned long> {\n    static bool Is(const ValueType& v) { return v.IsUint(); }\n    static unsigned long Get(const ValueType& v) { return v.GetUint(); }\n    static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }\n    static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }\n};\n#endif\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, int64_t> {\n    static bool Is(const ValueType& v) { return v.IsInt64(); }\n    static int64_t Get(const ValueType& v) { return v.GetInt64(); }\n    static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }\n    static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, uint64_t> {\n    static bool Is(const ValueType& v) { return v.IsUint64(); }\n    static uint64_t Get(const ValueType& v) { return v.GetUint64(); }\n    static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }\n    static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, double> {\n    static bool Is(const ValueType& v) { return v.IsDouble(); }\n    static double Get(const ValueType& v) { return v.GetDouble(); }\n    static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }\n    static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, float> {\n    static bool Is(const ValueType& v) { return v.IsFloat(); }\n    static float Get(const ValueType& v) { return v.GetFloat(); }\n    static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }\n    static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, const typename ValueType::Ch*> {\n    typedef const typename ValueType::Ch* StringType;\n    static bool Is(const ValueType& v) { return v.IsString(); }\n    static StringType Get(const ValueType& v) { return v.GetString(); }\n    static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }\n    static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }\n};\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {\n    typedef std::basic_string<typename ValueType::Ch> StringType;\n    static bool Is(const ValueType& v) { return v.IsString(); }\n    static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }\n    static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }\n};\n#endif\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::Array> {\n    typedef typename ValueType::Array ArrayType;\n    static bool Is(const ValueType& v) { return v.IsArray(); }\n    static ArrayType Get(ValueType& v) { return v.GetArray(); }\n    static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }\n    static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::ConstArray> {\n    typedef typename ValueType::ConstArray ArrayType;\n    static bool Is(const ValueType& v) { return v.IsArray(); }\n    static ArrayType Get(const ValueType& v) { return v.GetArray(); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::Object> {\n    typedef typename ValueType::Object ObjectType;\n    static bool Is(const ValueType& v) { return v.IsObject(); }\n    static ObjectType Get(ValueType& v) { return v.GetObject(); }\n    static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }\n    static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::ConstObject> {\n    typedef typename ValueType::ConstObject ObjectType;\n    static bool Is(const ValueType& v) { return v.IsObject(); }\n    static ObjectType Get(const ValueType& v) { return v.GetObject(); }\n};\n\n} // namespace internal\n\n// Forward declarations\ntemplate <bool, typename> class GenericArray;\ntemplate <bool, typename> class GenericObject;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue\n\n//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.\n/*!\n    A JSON value can be one of 7 types. This class is a variant type supporting\n    these types.\n\n    Use the Value if UTF8 and default allocator\n\n    \\tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)\n    \\tparam Allocator   Allocator type for allocating memory of object, array and string.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<> > \nclass GenericValue {\npublic:\n    //! Name-value pair in an object.\n    typedef GenericMember<Encoding, Allocator> Member;\n    typedef Encoding EncodingType;                  //!< Encoding type from template parameter.\n    typedef Allocator AllocatorType;                //!< Allocator type from template parameter.\n    typedef typename Encoding::Ch Ch;               //!< Character type derived from Encoding.\n    typedef GenericStringRef<Ch> StringRefType;     //!< Reference to a constant string\n    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;  //!< Member iterator for iterating in object.\n    typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator;  //!< Constant member iterator for iterating in object.\n    typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array.\n    typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.\n    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself.\n    typedef GenericArray<false, ValueType> Array;\n    typedef GenericArray<true, ValueType> ConstArray;\n    typedef GenericObject<false, ValueType> Object;\n    typedef GenericObject<true, ValueType> ConstObject;\n\n    //!@name Constructors and destructor.\n    //@{\n\n    //! Default constructor creates a null value.\n    GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {\n        rhs.data_.f.flags = kNullFlag; // give up contents\n    }\n#endif\n\nprivate:\n    //! Copy constructor is not permitted.\n    GenericValue(const GenericValue& rhs);\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Moving from a GenericDocument is not permitted.\n    template <typename StackAllocator>\n    GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);\n\n    //! Move assignment from a GenericDocument is not permitted.\n    template <typename StackAllocator>\n    GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);\n#endif\n\npublic:\n\n    //! Constructor with JSON value type.\n    /*! This creates a Value of specified type with default content.\n        \\param type Type of the value.\n        \\note Default content for number is zero.\n    */\n    explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {\n        static const uint16_t defaultFlags[] = {\n            kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,\n            kNumberAnyFlag\n        };\n        RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);\n        data_.f.flags = defaultFlags[type];\n\n        // Use ShortString to store empty string.\n        if (type == kStringType)\n            data_.ss.SetLength(0);\n    }\n\n    //! Explicit copy constructor (with allocator)\n    /*! Creates a copy of a Value by using the given Allocator\n        \\tparam SourceAllocator allocator of \\c rhs\n        \\param rhs Value to copy from (read-only)\n        \\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().\n        \\param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)\n        \\see CopyFrom()\n    */\n    template <typename SourceAllocator>\n    GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {\n        switch (rhs.GetType()) {\n        case kObjectType: {\n                SizeType count = rhs.data_.o.size;\n                Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));\n                const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();\n                for (SizeType i = 0; i < count; i++) {\n                    new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);\n                    new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);\n                }\n                data_.f.flags = kObjectFlag;\n                data_.o.size = data_.o.capacity = count;\n                SetMembersPointer(lm);\n            }\n            break;\n        case kArrayType: {\n                SizeType count = rhs.data_.a.size;\n                GenericValue* le = reinterpret_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));\n                const GenericValue<Encoding,SourceAllocator>* re = rhs.GetElementsPointer();\n                for (SizeType i = 0; i < count; i++)\n                    new (&le[i]) GenericValue(re[i], allocator, copyConstStrings);\n                data_.f.flags = kArrayFlag;\n                data_.a.size = data_.a.capacity = count;\n                SetElementsPointer(le);\n            }\n            break;\n        case kStringType:\n            if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) {\n                data_.f.flags = rhs.data_.f.flags;\n                data_  = *reinterpret_cast<const Data*>(&rhs.data_);\n            }\n            else\n                SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);\n            break;\n        default:\n            data_.f.flags = rhs.data_.f.flags;\n            data_  = *reinterpret_cast<const Data*>(&rhs.data_);\n            break;\n        }\n    }\n\n    //! Constructor for boolean value.\n    /*! \\param b Boolean value\n        \\note This constructor is limited to \\em real boolean values and rejects\n            implicitly converted types like arbitrary pointers.  Use an explicit cast\n            to \\c bool, if you want to construct a boolean JSON value in such cases.\n     */\n#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen\n    template <typename T>\n    explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT  // See #472\n#else\n    explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT\n#endif\n        : data_() {\n            // safe-guard against failing SFINAE\n            RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));\n            data_.f.flags = b ? kTrueFlag : kFalseFlag;\n    }\n\n    //! Constructor for int value.\n    explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.i64 = i;\n        data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;\n    }\n\n    //! Constructor for unsigned value.\n    explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.u64 = u; \n        data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);\n    }\n\n    //! Constructor for int64_t value.\n    explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.i64 = i64;\n        data_.f.flags = kNumberInt64Flag;\n        if (i64 >= 0) {\n            data_.f.flags |= kNumberUint64Flag;\n            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))\n                data_.f.flags |= kUintFlag;\n            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n                data_.f.flags |= kIntFlag;\n        }\n        else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n            data_.f.flags |= kIntFlag;\n    }\n\n    //! Constructor for uint64_t value.\n    explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.u64 = u64;\n        data_.f.flags = kNumberUint64Flag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))\n            data_.f.flags |= kInt64Flag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))\n            data_.f.flags |= kUintFlag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n            data_.f.flags |= kIntFlag;\n    }\n\n    //! Constructor for double value.\n    explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }\n\n    //! Constructor for float value.\n    explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; }\n\n    //! Constructor for constant string (i.e. do not make a copy of string)\n    GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }\n\n    //! Constructor for constant string (i.e. do not make a copy of string)\n    explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }\n\n    //! Constructor for copy-string (i.e. do make a copy of string)\n    GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }\n\n    //! Constructor for copy-string (i.e. do make a copy of string)\n    GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Constructor for copy-string from a string object (i.e. do make a copy of string)\n    /*! \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n     */\n    GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }\n#endif\n\n    //! Constructor for Array.\n    /*!\n        \\param a An array obtained by \\c GetArray().\n        \\note \\c Array is always pass-by-value.\n        \\note the source array is moved into this value and the sourec array becomes empty.\n    */\n    GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {\n        a.value_.data_ = Data();\n        a.value_.data_.f.flags = kArrayFlag;\n    }\n\n    //! Constructor for Object.\n    /*!\n        \\param o An object obtained by \\c GetObject().\n        \\note \\c Object is always pass-by-value.\n        \\note the source object is moved into this value and the sourec object becomes empty.\n    */\n    GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {\n        o.value_.data_ = Data();\n        o.value_.data_.f.flags = kObjectFlag;\n    }\n\n    //! Destructor.\n    /*! Need to destruct elements of array, members of object, or copy-string.\n    */\n    ~GenericValue() {\n        if (Allocator::kNeedFree) { // Shortcut by Allocator's trait\n            switch(data_.f.flags) {\n            case kArrayFlag:\n                {\n                    GenericValue* e = GetElementsPointer();\n                    for (GenericValue* v = e; v != e + data_.a.size; ++v)\n                        v->~GenericValue();\n                    Allocator::Free(e);\n                }\n                break;\n\n            case kObjectFlag:\n                for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)\n                    m->~Member();\n                Allocator::Free(GetMembersPointer());\n                break;\n\n            case kCopyStringFlag:\n                Allocator::Free(const_cast<Ch*>(GetStringPointer()));\n                break;\n\n            default:\n                break;  // Do nothing for other types.\n            }\n        }\n    }\n\n    //@}\n\n    //!@name Assignment operators\n    //@{\n\n    //! Assignment with move semantics.\n    /*! \\param rhs Source of the assignment. It will become a null value after assignment.\n    */\n    GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {\n        if (RAPIDJSON_LIKELY(this != &rhs)) {\n            this->~GenericValue();\n            RawAssign(rhs);\n        }\n        return *this;\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move assignment in C++11\n    GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {\n        return *this = rhs.Move();\n    }\n#endif\n\n    //! Assignment of constant string reference (no copy)\n    /*! \\param str Constant string reference to be assigned\n        \\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.\n        \\see GenericStringRef, operator=(T)\n    */\n    GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {\n        GenericValue s(str);\n        return *this = s;\n    }\n\n    //! Assignment with primitive types.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param value The value to be assigned.\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref SetString(const Ch*, Allocator&) (for copying) or\n            \\ref StringRef() (to explicitly mark the pointer as constant) instead.\n            All other pointer types would implicitly convert to \\c bool,\n            use \\ref SetBool() instead.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))\n    operator=(T value) {\n        GenericValue v(value);\n        return *this = v;\n    }\n\n    //! Deep-copy assignment from Value\n    /*! Assigns a \\b copy of the Value to the current Value object\n        \\tparam SourceAllocator Allocator type of \\c rhs\n        \\param rhs Value to copy from (read-only)\n        \\param allocator Allocator to use for copying\n        \\param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)\n     */\n    template <typename SourceAllocator>\n    GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {\n        RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));\n        this->~GenericValue();\n        new (this) GenericValue(rhs, allocator, copyConstStrings);\n        return *this;\n    }\n\n    //! Exchange the contents of this value with those of other.\n    /*!\n        \\param other Another value.\n        \\note Constant complexity.\n    */\n    GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {\n        GenericValue temp;\n        temp.RawAssign(*this);\n        RawAssign(other);\n        other.RawAssign(temp);\n        return *this;\n    }\n\n    //! free-standing swap function helper\n    /*!\n        Helper function to enable support for common swap implementation pattern based on \\c std::swap:\n        \\code\n        void swap(MyClass& a, MyClass& b) {\n            using std::swap;\n            swap(a.value, b.value);\n            // ...\n        }\n        \\endcode\n        \\see Swap()\n     */\n    friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }\n\n    //! Prepare Value for move semantics\n    /*! \\return *this */\n    GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }\n    //@}\n\n    //!@name Equal-to and not-equal-to operators\n    //@{\n    //! Equal-to operator\n    /*!\n        \\note If an object contains duplicated named member, comparing equality with any object is always \\c false.\n        \\note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings).\n    */\n    template <typename SourceAllocator>\n    bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {\n        typedef GenericValue<Encoding, SourceAllocator> RhsType;\n        if (GetType() != rhs.GetType())\n            return false;\n\n        switch (GetType()) {\n        case kObjectType: // Warning: O(n^2) inner-loop\n            if (data_.o.size != rhs.data_.o.size)\n                return false;           \n            for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {\n                typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);\n                if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)\n                    return false;\n            }\n            return true;\n            \n        case kArrayType:\n            if (data_.a.size != rhs.data_.a.size)\n                return false;\n            for (SizeType i = 0; i < data_.a.size; i++)\n                if ((*this)[i] != rhs[i])\n                    return false;\n            return true;\n\n        case kStringType:\n            return StringEqual(rhs);\n\n        case kNumberType:\n            if (IsDouble() || rhs.IsDouble()) {\n                double a = GetDouble();     // May convert from integer to double.\n                double b = rhs.GetDouble(); // Ditto\n                return a >= b && a <= b;    // Prevent -Wfloat-equal\n            }\n            else\n                return data_.n.u64 == rhs.data_.n.u64;\n\n        default:\n            return true;\n        }\n    }\n\n    //! Equal-to operator with const C-string pointer\n    bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Equal-to operator with string object\n    /*! \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n     */\n    bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }\n#endif\n\n    //! Equal-to operator with primitive types\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c double, \\c true, \\c false\n    */\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }\n\n    //! Not-equal-to operator\n    /*! \\return !(*this == rhs)\n     */\n    template <typename SourceAllocator>\n    bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }\n\n    //! Not-equal-to operator with const C-string pointer\n    bool operator!=(const Ch* rhs) const { return !(*this == rhs); }\n\n    //! Not-equal-to operator with arbitrary types\n    /*! \\return !(*this == rhs)\n     */\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }\n\n    //! Equal-to operator with arbitrary types (symmetric version)\n    /*! \\return (rhs == lhs)\n     */\n    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }\n\n    //! Not-Equal-to operator with arbitrary types (symmetric version)\n    /*! \\return !(rhs == lhs)\n     */\n    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }\n    //@}\n\n    //!@name Type\n    //@{\n\n    Type GetType()  const { return static_cast<Type>(data_.f.flags & kTypeMask); }\n    bool IsNull()   const { return data_.f.flags == kNullFlag; }\n    bool IsFalse()  const { return data_.f.flags == kFalseFlag; }\n    bool IsTrue()   const { return data_.f.flags == kTrueFlag; }\n    bool IsBool()   const { return (data_.f.flags & kBoolFlag) != 0; }\n    bool IsObject() const { return data_.f.flags == kObjectFlag; }\n    bool IsArray()  const { return data_.f.flags == kArrayFlag; }\n    bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }\n    bool IsInt()    const { return (data_.f.flags & kIntFlag) != 0; }\n    bool IsUint()   const { return (data_.f.flags & kUintFlag) != 0; }\n    bool IsInt64()  const { return (data_.f.flags & kInt64Flag) != 0; }\n    bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }\n    bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }\n    bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }\n\n    // Checks whether a number can be losslessly converted to a double.\n    bool IsLosslessDouble() const {\n        if (!IsNumber()) return false;\n        if (IsUint64()) {\n            uint64_t u = GetUint64();\n            volatile double d = static_cast<double>(u);\n            return (d >= 0.0)\n                && (d < static_cast<double>((std::numeric_limits<uint64_t>::max)()))\n                && (u == static_cast<uint64_t>(d));\n        }\n        if (IsInt64()) {\n            int64_t i = GetInt64();\n            volatile double d = static_cast<double>(i);\n            return (d >= static_cast<double>((std::numeric_limits<int64_t>::min)()))\n                && (d < static_cast<double>((std::numeric_limits<int64_t>::max)()))\n                && (i == static_cast<int64_t>(d));\n        }\n        return true; // double, int, uint are always lossless\n    }\n\n    // Checks whether a number is a float (possible lossy).\n    bool IsFloat() const  {\n        if ((data_.f.flags & kDoubleFlag) == 0)\n            return false;\n        double d = GetDouble();\n        return d >= -3.4028234e38 && d <= 3.4028234e38;\n    }\n    // Checks whether a number can be losslessly converted to a float.\n    bool IsLosslessFloat() const {\n        if (!IsNumber()) return false;\n        double a = GetDouble();\n        if (a < static_cast<double>(-(std::numeric_limits<float>::max)())\n                || a > static_cast<double>((std::numeric_limits<float>::max)()))\n            return false;\n        double b = static_cast<double>(static_cast<float>(a));\n        return a >= b && a <= b;    // Prevent -Wfloat-equal\n    }\n\n    //@}\n\n    //!@name Null\n    //@{\n\n    GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }\n\n    //@}\n\n    //!@name Bool\n    //@{\n\n    bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }\n    //!< Set boolean value\n    /*! \\post IsBool() == true */\n    GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }\n\n    //@}\n\n    //!@name Object\n    //@{\n\n    //! Set this value as an empty object.\n    /*! \\post IsObject() == true */\n    GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }\n\n    //! Get the number of members in the object.\n    SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }\n\n    //! Get the capacity of object.\n    SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }\n\n    //! Check whether the object is empty.\n    bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }\n\n    //! Get a value from an object associated with the name.\n    /*! \\pre IsObject() == true\n        \\tparam T Either \\c Ch or \\c const \\c Ch (template used for disambiguation with \\ref operator[](SizeType))\n        \\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.\n        Since 0.2, if the name is not correct, it will assert.\n        If user is unsure whether a member exists, user should use HasMember() first.\n        A better approach is to use FindMember().\n        \\note Linear time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {\n        GenericValue n(StringRef(name));\n        return (*this)[n];\n    }\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n    //! Get a value from an object associated with the name.\n    /*! \\pre IsObject() == true\n        \\tparam SourceAllocator Allocator of the \\c name value\n\n        \\note Compared to \\ref operator[](T*), this version is faster because it does not need a StrLen().\n        And it can also handle strings with embedded null characters.\n\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator member = FindMember(name);\n        if (member != MemberEnd())\n            return member->value;\n        else {\n            RAPIDJSON_ASSERT(false);    // see above note\n\n            // This will generate -Wexit-time-destructors in clang\n            // static GenericValue NullValue;\n            // return NullValue;\n\n            // Use static buffer and placement-new to prevent destruction\n            static char buffer[sizeof(GenericValue)];\n            return *new (buffer) GenericValue();\n        }\n    }\n    template <typename SourceAllocator>\n    const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Get a value from an object associated with name (string object).\n    GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }\n    const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }\n#endif\n\n    //! Const member iterator\n    /*! \\pre IsObject() == true */\n    ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }\n    //! Const \\em past-the-end member iterator\n    /*! \\pre IsObject() == true */\n    ConstMemberIterator MemberEnd() const   { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }\n    //! Member iterator\n    /*! \\pre IsObject() == true */\n    MemberIterator MemberBegin()            { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }\n    //! \\em Past-the-end member iterator\n    /*! \\pre IsObject() == true */\n    MemberIterator MemberEnd()              { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }\n\n    //! Request the object to have enough capacity to store members.\n    /*! \\param newCapacity  The capacity that the object at least need to have.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note Linear time complexity.\n    */\n    GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {\n        RAPIDJSON_ASSERT(IsObject());\n        if (newCapacity > data_.o.capacity) {\n            SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));\n            data_.o.capacity = newCapacity;\n        }\n        return *this;\n    }\n\n    //! Check whether a member exists in the object.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Check whether a member exists in the object with string object.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }\n#endif\n\n    //! Check whether a member exists in the object with GenericValue name.\n    /*!\n        This version is faster because it does not need a StrLen(). It can also handle string with null character.\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }\n\n    //! Find member by name.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n\n        \\note Earlier versions of Rapidjson returned a \\c NULL pointer, in case\n            the requested member doesn't exist. For consistency with e.g.\n            \\c std::map, this has been changed to MemberEnd() now.\n        \\note Linear time complexity.\n    */\n    MemberIterator FindMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return FindMember(n);\n    }\n\n    ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n    //! Find member by name.\n    /*!\n        This version is faster because it does not need a StrLen(). It can also handle string with null character.\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n\n        \\note Earlier versions of Rapidjson returned a \\c NULL pointer, in case\n            the requested member doesn't exist. For consistency with e.g.\n            \\c std::map, this has been changed to MemberEnd() now.\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(name.IsString());\n        MemberIterator member = MemberBegin();\n        for ( ; member != MemberEnd(); ++member)\n            if (name.StringEqual(member->name))\n                break;\n        return member;\n    }\n    template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Find member by string object name.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n    */\n    MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); }\n    ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); }\n#endif\n\n    //! Add a member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value Value of any type.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c name and \\c value will be transferred to this object on success.\n        \\pre  IsObject() && name.IsString()\n        \\post name.IsNull() && value.IsNull()\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(name.IsString());\n\n        ObjectData& o = data_.o;\n        if (o.size >= o.capacity)\n            MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);\n        Member* members = GetMembersPointer();\n        members[o.size].name.RawAssign(name);\n        members[o.size].value.RawAssign(value);\n        o.size++;\n        return *this;\n    }\n\n    //! Add a constant string value as member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Add a string object as member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {\n        GenericValue v(value, allocator);\n        return AddMember(name, v, allocator);\n    }\n#endif\n\n    //! Add any primitive value as member (name-value pair) to the object.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param name A string value as name of member.\n        \\param value Value of primitive type \\c T as value of member\n        \\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref AddMember(StringRefType, GenericValue&, Allocator&) or \\ref\n            AddMember(StringRefType, StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized Constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    AddMember(GenericValue& name, T value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n\n    //! Add a member (name-value pair) to the object.\n    /*! \\param name A constant string reference as name of member.\n        \\param value Value of any type.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c value will be transferred to this object on success.\n        \\pre  IsObject()\n        \\post value.IsNull()\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n\n    //! Add a constant string value as member (name-value pair) to the object.\n    /*! \\param name A constant string reference as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n    //! Add any primitive value as member (name-value pair) to the object.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param name A constant string reference as name of member.\n        \\param value Value of primitive type \\c T as value of member\n        \\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref AddMember(StringRefType, GenericValue&, Allocator&) or \\ref\n            AddMember(StringRefType, StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized Constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    AddMember(StringRefType name, T value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n\n    //! Remove all members in the object.\n    /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.\n        \\note Linear time complexity.\n    */\n    void RemoveAllMembers() {\n        RAPIDJSON_ASSERT(IsObject()); \n        for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)\n            m->~Member();\n        data_.o.size = 0;\n    }\n\n    //! Remove a member in object by its name.\n    /*! \\param name Name of member to be removed.\n        \\return Whether the member existed.\n        \\note This function may reorder the object members. Use \\ref\n            EraseMember(ConstMemberIterator) if you need to preserve the\n            relative order of the remaining members.\n        \\note Linear time complexity.\n    */\n    bool RemoveMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return RemoveMember(n);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }\n#endif\n\n    template <typename SourceAllocator>\n    bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator m = FindMember(name);\n        if (m != MemberEnd()) {\n            RemoveMember(m);\n            return true;\n        }\n        else\n            return false;\n    }\n\n    //! Remove a member in object by iterator.\n    /*! \\param m member iterator (obtained by FindMember() or MemberBegin()).\n        \\return the new iterator after removal.\n        \\note This function may reorder the object members. Use \\ref\n            EraseMember(ConstMemberIterator) if you need to preserve the\n            relative order of the remaining members.\n        \\note Constant time complexity.\n    */\n    MemberIterator RemoveMember(MemberIterator m) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(data_.o.size > 0);\n        RAPIDJSON_ASSERT(GetMembersPointer() != 0);\n        RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());\n\n        MemberIterator last(GetMembersPointer() + (data_.o.size - 1));\n        if (data_.o.size > 1 && m != last)\n            *m = *last; // Move the last one to this place\n        else\n            m->~Member(); // Only one left, just destroy\n        --data_.o.size;\n        return m;\n    }\n\n    //! Remove a member from an object by iterator.\n    /*! \\param pos iterator to the member to remove\n        \\pre IsObject() == true && \\ref MemberBegin() <= \\c pos < \\ref MemberEnd()\n        \\return Iterator following the removed element.\n            If the iterator \\c pos refers to the last element, the \\ref MemberEnd() iterator is returned.\n        \\note This function preserves the relative order of the remaining object\n            members. If you do not need this, use the more efficient \\ref RemoveMember(MemberIterator).\n        \\note Linear time complexity.\n    */\n    MemberIterator EraseMember(ConstMemberIterator pos) {\n        return EraseMember(pos, pos +1);\n    }\n\n    //! Remove members in the range [first, last) from an object.\n    /*! \\param first iterator to the first member to remove\n        \\param last  iterator following the last member to remove\n        \\pre IsObject() == true && \\ref MemberBegin() <= \\c first <= \\c last <= \\ref MemberEnd()\n        \\return Iterator following the last removed element.\n        \\note This function preserves the relative order of the remaining object\n            members.\n        \\note Linear time complexity.\n    */\n    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(data_.o.size > 0);\n        RAPIDJSON_ASSERT(GetMembersPointer() != 0);\n        RAPIDJSON_ASSERT(first >= MemberBegin());\n        RAPIDJSON_ASSERT(first <= last);\n        RAPIDJSON_ASSERT(last <= MemberEnd());\n\n        MemberIterator pos = MemberBegin() + (first - MemberBegin());\n        for (MemberIterator itr = pos; itr != last; ++itr)\n            itr->~Member();\n        std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));\n        data_.o.size -= static_cast<SizeType>(last - first);\n        return pos;\n    }\n\n    //! Erase a member in object by its name.\n    /*! \\param name Name of member to be removed.\n        \\return Whether the member existed.\n        \\note Linear time complexity.\n    */\n    bool EraseMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return EraseMember(n);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }\n#endif\n\n    template <typename SourceAllocator>\n    bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator m = FindMember(name);\n        if (m != MemberEnd()) {\n            EraseMember(m);\n            return true;\n        }\n        else\n            return false;\n    }\n\n    Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }\n    ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }\n\n    //@}\n\n    //!@name Array\n    //@{\n\n    //! Set this value as an empty array.\n    /*! \\post IsArray == true */\n    GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }\n\n    //! Get the number of elements in array.\n    SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }\n\n    //! Get the capacity of array.\n    SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }\n\n    //! Check whether the array is empty.\n    bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }\n\n    //! Remove all elements in the array.\n    /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.\n        \\note Linear time complexity.\n    */\n    void Clear() {\n        RAPIDJSON_ASSERT(IsArray()); \n        GenericValue* e = GetElementsPointer();\n        for (GenericValue* v = e; v != e + data_.a.size; ++v)\n            v->~GenericValue();\n        data_.a.size = 0;\n    }\n\n    //! Get an element from array by index.\n    /*! \\pre IsArray() == true\n        \\param index Zero-based index of element.\n        \\see operator[](T*)\n    */\n    GenericValue& operator[](SizeType index) {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(index < data_.a.size);\n        return GetElementsPointer()[index];\n    }\n    const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }\n\n    //! Element iterator\n    /*! \\pre IsArray() == true */\n    ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }\n    //! \\em Past-the-end element iterator\n    /*! \\pre IsArray() == true */\n    ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }\n    //! Constant element iterator\n    /*! \\pre IsArray() == true */\n    ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }\n    //! Constant \\em past-the-end element iterator\n    /*! \\pre IsArray() == true */\n    ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }\n\n    //! Request the array to have enough capacity to store elements.\n    /*! \\param newCapacity  The capacity that the array at least need to have.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note Linear time complexity.\n    */\n    GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {\n        RAPIDJSON_ASSERT(IsArray());\n        if (newCapacity > data_.a.capacity) {\n            SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));\n            data_.a.capacity = newCapacity;\n        }\n        return *this;\n    }\n\n    //! Append a GenericValue at the end of the array.\n    /*! \\param value        Value to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\post value.IsNull() == true\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c value will be transferred to this array on success.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n        \\note Amortized constant time complexity.\n    */\n    GenericValue& PushBack(GenericValue& value, Allocator& allocator) {\n        RAPIDJSON_ASSERT(IsArray());\n        if (data_.a.size >= data_.a.capacity)\n            Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);\n        GetElementsPointer()[data_.a.size++].RawAssign(value);\n        return *this;\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {\n        return PushBack(value, allocator);\n    }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n    //! Append a constant string reference at the end of the array.\n    /*! \\param value        Constant string reference to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\return The value itself for fluent API.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n        \\note Amortized constant time complexity.\n        \\see GenericStringRef\n    */\n    GenericValue& PushBack(StringRefType value, Allocator& allocator) {\n        return (*this).template PushBack<StringRefType>(value, allocator);\n    }\n\n    //! Append a primitive value at the end of the array.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param value Value of primitive type T to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\return The value itself for fluent API.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref PushBack(GenericValue&, Allocator&) or \\ref\n            PushBack(StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    PushBack(T value, Allocator& allocator) {\n        GenericValue v(value);\n        return PushBack(v, allocator);\n    }\n\n    //! Remove the last element in the array.\n    /*!\n        \\note Constant time complexity.\n    */\n    GenericValue& PopBack() {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(!Empty());\n        GetElementsPointer()[--data_.a.size].~GenericValue();\n        return *this;\n    }\n\n    //! Remove an element of array by iterator.\n    /*!\n        \\param pos iterator to the element to remove\n        \\pre IsArray() == true && \\ref Begin() <= \\c pos < \\ref End()\n        \\return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.\n        \\note Linear time complexity.\n    */\n    ValueIterator Erase(ConstValueIterator pos) {\n        return Erase(pos, pos + 1);\n    }\n\n    //! Remove elements in the range [first, last) of the array.\n    /*!\n        \\param first iterator to the first element to remove\n        \\param last  iterator following the last element to remove\n        \\pre IsArray() == true && \\ref Begin() <= \\c first <= \\c last <= \\ref End()\n        \\return Iterator following the last removed element.\n        \\note Linear time complexity.\n    */\n    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(data_.a.size > 0);\n        RAPIDJSON_ASSERT(GetElementsPointer() != 0);\n        RAPIDJSON_ASSERT(first >= Begin());\n        RAPIDJSON_ASSERT(first <= last);\n        RAPIDJSON_ASSERT(last <= End());\n        ValueIterator pos = Begin() + (first - Begin());\n        for (ValueIterator itr = pos; itr != last; ++itr)\n            itr->~GenericValue();\n        std::memmove(static_cast<void*>(pos), last, static_cast<size_t>(End() - last) * sizeof(GenericValue));\n        data_.a.size -= static_cast<SizeType>(last - first);\n        return pos;\n    }\n\n    Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }\n    ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }\n\n    //@}\n\n    //!@name Number\n    //@{\n\n    int GetInt() const          { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag);   return data_.n.i.i;   }\n    unsigned GetUint() const    { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag);  return data_.n.u.u;   }\n    int64_t GetInt64() const    { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }\n    uint64_t GetUint64() const  { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }\n\n    //! Get the value as double type.\n    /*! \\note If the value is 64-bit integer type, it may lose precision. Use \\c IsLosslessDouble() to check whether the converison is lossless.\n    */\n    double GetDouble() const {\n        RAPIDJSON_ASSERT(IsNumber());\n        if ((data_.f.flags & kDoubleFlag) != 0)                return data_.n.d;   // exact type, no conversion.\n        if ((data_.f.flags & kIntFlag) != 0)                   return data_.n.i.i; // int -> double\n        if ((data_.f.flags & kUintFlag) != 0)                  return data_.n.u.u; // unsigned -> double\n        if ((data_.f.flags & kInt64Flag) != 0)                 return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)\n        RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0);  return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)\n    }\n\n    //! Get the value as float type.\n    /*! \\note If the value is 64-bit integer type, it may lose precision. Use \\c IsLosslessFloat() to check whether the converison is lossless.\n    */\n    float GetFloat() const {\n        return static_cast<float>(GetDouble());\n    }\n\n    GenericValue& SetInt(int i)             { this->~GenericValue(); new (this) GenericValue(i);    return *this; }\n    GenericValue& SetUint(unsigned u)       { this->~GenericValue(); new (this) GenericValue(u);    return *this; }\n    GenericValue& SetInt64(int64_t i64)     { this->~GenericValue(); new (this) GenericValue(i64);  return *this; }\n    GenericValue& SetUint64(uint64_t u64)   { this->~GenericValue(); new (this) GenericValue(u64);  return *this; }\n    GenericValue& SetDouble(double d)       { this->~GenericValue(); new (this) GenericValue(d);    return *this; }\n    GenericValue& SetFloat(float f)         { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; }\n\n    //@}\n\n    //!@name String\n    //@{\n\n    const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }\n\n    //! Get the length of string.\n    /*! Since rapidjson permits \"\\\\u0000\" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().\n    */\n    SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }\n\n    //! Set this value as a string without copying source string.\n    /*! This version has better performance with supplied length, and also support string containing null character.\n        \\param s source string pointer. \n        \\param length The length of source string, excluding the trailing null terminator.\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() == s && GetStringLength() == length\n        \\see SetString(StringRefType)\n    */\n    GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }\n\n    //! Set this value as a string without copying source string.\n    /*! \\param s source string reference\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() == s && GetStringLength() == s.length\n    */\n    GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }\n\n    //! Set this value as a string by copying from source string.\n    /*! This version has better performance with supplied length, and also support string containing null character.\n        \\param s source string. \n        \\param length The length of source string, excluding the trailing null terminator.\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }\n\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string. \n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }\n\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string reference\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string.\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()\n        \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n    */\n    GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }\n#endif\n\n    //@}\n\n    //!@name Array\n    //@{\n\n    //! Templated version for checking whether this value is type T.\n    /*!\n        \\tparam T Either \\c bool, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c double, \\c float, \\c const \\c char*, \\c std::basic_string<Ch>\n    */\n    template <typename T>\n    bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }\n\n    template <typename T>\n    T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }\n\n    template <typename T>\n    T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }\n\n    template<typename T>\n    ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }\n\n    template<typename T>\n    ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }\n\n    //@}\n\n    //! Generate events of this value to a Handler.\n    /*! This function adopts the GoF visitor pattern.\n        Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.\n        It can also be used to deep clone this value via GenericDocument, which is also a Handler.\n        \\tparam Handler type of handler.\n        \\param handler An object implementing concept Handler.\n    */\n    template <typename Handler>\n    bool Accept(Handler& handler) const {\n        switch(GetType()) {\n        case kNullType:     return handler.Null();\n        case kFalseType:    return handler.Bool(false);\n        case kTrueType:     return handler.Bool(true);\n\n        case kObjectType:\n            if (RAPIDJSON_UNLIKELY(!handler.StartObject()))\n                return false;\n            for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {\n                RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.\n                if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))\n                    return false;\n                if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))\n                    return false;\n            }\n            return handler.EndObject(data_.o.size);\n\n        case kArrayType:\n            if (RAPIDJSON_UNLIKELY(!handler.StartArray()))\n                return false;\n            for (const GenericValue* v = Begin(); v != End(); ++v)\n                if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))\n                    return false;\n            return handler.EndArray(data_.a.size);\n    \n        case kStringType:\n            return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);\n    \n        default:\n            RAPIDJSON_ASSERT(GetType() == kNumberType);\n            if (IsDouble())         return handler.Double(data_.n.d);\n            else if (IsInt())       return handler.Int(data_.n.i.i);\n            else if (IsUint())      return handler.Uint(data_.n.u.u);\n            else if (IsInt64())     return handler.Int64(data_.n.i64);\n            else                    return handler.Uint64(data_.n.u64);\n        }\n    }\n\nprivate:\n    template <typename, typename> friend class GenericValue;\n    template <typename, typename, typename> friend class GenericDocument;\n\n    enum {\n        kBoolFlag       = 0x0008,\n        kNumberFlag     = 0x0010,\n        kIntFlag        = 0x0020,\n        kUintFlag       = 0x0040,\n        kInt64Flag      = 0x0080,\n        kUint64Flag     = 0x0100,\n        kDoubleFlag     = 0x0200,\n        kStringFlag     = 0x0400,\n        kCopyFlag       = 0x0800,\n        kInlineStrFlag  = 0x1000,\n\n        // Initial flags of different types.\n        kNullFlag = kNullType,\n        kTrueFlag = kTrueType | kBoolFlag,\n        kFalseFlag = kFalseType | kBoolFlag,\n        kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,\n        kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,\n        kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,\n        kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,\n        kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,\n        kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,\n        kConstStringFlag = kStringType | kStringFlag,\n        kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,\n        kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,\n        kObjectFlag = kObjectType,\n        kArrayFlag = kArrayType,\n\n        kTypeMask = 0x07\n    };\n\n    static const SizeType kDefaultArrayCapacity = 16;\n    static const SizeType kDefaultObjectCapacity = 16;\n\n    struct Flag {\n#if RAPIDJSON_48BITPOINTER_OPTIMIZATION\n        char payload[sizeof(SizeType) * 2 + 6];     // 2 x SizeType + lower 48-bit pointer\n#elif RAPIDJSON_64BIT\n        char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes\n#else\n        char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes\n#endif\n        uint16_t flags;\n    };\n\n    struct String {\n        SizeType length;\n        SizeType hashcode;  //!< reserved\n        const Ch* str;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars\n    // (excluding the terminating zero) and store a value to determine the length of the contained\n    // string in the last character str[LenPos] by storing \"MaxSize - length\" there. If the string\n    // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as\n    // the string terminator as well. For getting the string length back from that value just use\n    // \"MaxSize - str[LenPos]\".\n    // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,\n    // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).\n    struct ShortString {\n        enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };\n        Ch str[MaxChars];\n\n        inline static bool Usable(SizeType len) { return                       (MaxSize >= len); }\n        inline void     SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize -  len); }\n        inline SizeType GetLength() const       { return  static_cast<SizeType>(MaxSize -  str[LenPos]); }\n    };  // at most as many bytes as \"String\" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // By using proper binary layout, retrieval of different integer types do not need conversions.\n    union Number {\n#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN\n        struct I {\n            int i;\n            char padding[4];\n        }i;\n        struct U {\n            unsigned u;\n            char padding2[4];\n        }u;\n#else\n        struct I {\n            char padding[4];\n            int i;\n        }i;\n        struct U {\n            char padding2[4];\n            unsigned u;\n        }u;\n#endif\n        int64_t i64;\n        uint64_t u64;\n        double d;\n    };  // 8 bytes\n\n    struct ObjectData {\n        SizeType size;\n        SizeType capacity;\n        Member* members;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    struct ArrayData {\n        SizeType size;\n        SizeType capacity;\n        GenericValue* elements;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    union Data {\n        String s;\n        ShortString ss;\n        Number n;\n        ObjectData o;\n        ArrayData a;\n        Flag f;\n    };  // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION\n\n    RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }\n    RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }\n    RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }\n    RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }\n    RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }\n    RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }\n\n    // Initialize this value as array with initial data, without calling destructor.\n    void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {\n        data_.f.flags = kArrayFlag;\n        if (count) {\n            GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));\n            SetElementsPointer(e);\n            std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue));\n        }\n        else\n            SetElementsPointer(0);\n        data_.a.size = data_.a.capacity = count;\n    }\n\n    //! Initialize this value as object with initial data, without calling destructor.\n    void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {\n        data_.f.flags = kObjectFlag;\n        if (count) {\n            Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));\n            SetMembersPointer(m);\n            std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));\n        }\n        else\n            SetMembersPointer(0);\n        data_.o.size = data_.o.capacity = count;\n    }\n\n    //! Initialize this value as constant string, without calling destructor.\n    void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {\n        data_.f.flags = kConstStringFlag;\n        SetStringPointer(s);\n        data_.s.length = s.length;\n    }\n\n    //! Initialize this value as copy string with initial data, without calling destructor.\n    void SetStringRaw(StringRefType s, Allocator& allocator) {\n        Ch* str = 0;\n        if (ShortString::Usable(s.length)) {\n            data_.f.flags = kShortStringFlag;\n            data_.ss.SetLength(s.length);\n            str = data_.ss.str;\n        } else {\n            data_.f.flags = kCopyStringFlag;\n            data_.s.length = s.length;\n            str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));\n            SetStringPointer(str);\n        }\n        std::memcpy(str, s, s.length * sizeof(Ch));\n        str[s.length] = '\\0';\n    }\n\n    //! Assignment without calling destructor\n    void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {\n        data_ = rhs.data_;\n        // data_.f.flags = rhs.data_.f.flags;\n        rhs.data_.f.flags = kNullFlag;\n    }\n\n    template <typename SourceAllocator>\n    bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {\n        RAPIDJSON_ASSERT(IsString());\n        RAPIDJSON_ASSERT(rhs.IsString());\n\n        const SizeType len1 = GetStringLength();\n        const SizeType len2 = rhs.GetStringLength();\n        if(len1 != len2) { return false; }\n\n        const Ch* const str1 = GetString();\n        const Ch* const str2 = rhs.GetString();\n        if(str1 == str2) { return true; } // fast path for constant string\n\n        return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);\n    }\n\n    Data data_;\n};\n\n//! GenericValue with UTF8 encoding\ntypedef GenericValue<UTF8<> > Value;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericDocument \n\n//! A document for parsing JSON text as DOM.\n/*!\n    \\note implements Handler concept\n    \\tparam Encoding Encoding for both parsing and string storage.\n    \\tparam Allocator Allocator for allocating memory for the DOM\n    \\tparam StackAllocator Allocator for allocating memory for stack during parsing.\n    \\warning Although GenericDocument inherits from GenericValue, the API does \\b not provide any virtual functions, especially no virtual destructor.  To avoid memory leaks, do not \\c delete a GenericDocument object via a pointer to a GenericValue.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>\nclass GenericDocument : public GenericValue<Encoding, Allocator> {\npublic:\n    typedef typename Encoding::Ch Ch;                       //!< Character type derived from Encoding.\n    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of the document.\n    typedef Allocator AllocatorType;                        //!< Allocator type from template parameter.\n\n    //! Constructor\n    /*! Creates an empty document of specified type.\n        \\param type             Mandatory type of object to create.\n        \\param allocator        Optional allocator for allocating memory.\n        \\param stackCapacity    Optional initial capacity of stack in bytes.\n        \\param stackAllocator   Optional allocator for allocating memory for stack.\n    */\n    explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :\n        GenericValue<Encoding, Allocator>(type),  allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n    }\n\n    //! Constructor\n    /*! Creates an empty document which type is Null. \n        \\param allocator        Optional allocator for allocating memory.\n        \\param stackCapacity    Optional initial capacity of stack in bytes.\n        \\param stackAllocator   Optional allocator for allocating memory for stack.\n    */\n    GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : \n        allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT\n        : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document\n          allocator_(rhs.allocator_),\n          ownAllocator_(rhs.ownAllocator_),\n          stack_(std::move(rhs.stack_)),\n          parseResult_(rhs.parseResult_)\n    {\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.parseResult_ = ParseResult();\n    }\n#endif\n\n    ~GenericDocument() {\n        Destroy();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move assignment in C++11\n    GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT\n    {\n        // The cast to ValueType is necessary here, because otherwise it would\n        // attempt to call GenericValue's templated assignment operator.\n        ValueType::operator=(std::forward<ValueType>(rhs));\n\n        // Calling the destructor here would prematurely call stack_'s destructor\n        Destroy();\n\n        allocator_ = rhs.allocator_;\n        ownAllocator_ = rhs.ownAllocator_;\n        stack_ = std::move(rhs.stack_);\n        parseResult_ = rhs.parseResult_;\n\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.parseResult_ = ParseResult();\n\n        return *this;\n    }\n#endif\n\n    //! Exchange the contents of this document with those of another.\n    /*!\n        \\param rhs Another document.\n        \\note Constant complexity.\n        \\see GenericValue::Swap\n    */\n    GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {\n        ValueType::Swap(rhs);\n        stack_.Swap(rhs.stack_);\n        internal::Swap(allocator_, rhs.allocator_);\n        internal::Swap(ownAllocator_, rhs.ownAllocator_);\n        internal::Swap(parseResult_, rhs.parseResult_);\n        return *this;\n    }\n\n    // Allow Swap with ValueType.\n    // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names.\n    using ValueType::Swap;\n\n    //! free-standing swap function helper\n    /*!\n        Helper function to enable support for common swap implementation pattern based on \\c std::swap:\n        \\code\n        void swap(MyClass& a, MyClass& b) {\n            using std::swap;\n            swap(a.doc, b.doc);\n            // ...\n        }\n        \\endcode\n        \\see Swap()\n     */\n    friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }\n\n    //! Populate this document by a generator which produces SAX events.\n    /*! \\tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.\n        \\param g Generator functor which sends SAX events to the parameter.\n        \\return The document itself for fluent API.\n    */\n    template <typename Generator>\n    GenericDocument& Populate(Generator& g) {\n        ClearStackOnExit scope(*this);\n        if (g(*this)) {\n            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object\n            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document\n        }\n        return *this;\n    }\n\n    //!@name Parse from stream\n    //!@{\n\n    //! Parse JSON text from an input stream (with Encoding conversion)\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam SourceEncoding Encoding of input stream\n        \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags, typename SourceEncoding, typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(\n            stack_.HasAllocator() ? &stack_.GetAllocator() : 0);\n        ClearStackOnExit scope(*this);\n        parseResult_ = reader.template Parse<parseFlags>(is, *this);\n        if (parseResult_) {\n            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object\n            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document\n        }\n        return *this;\n    }\n\n    //! Parse JSON text from an input stream\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags, typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        return ParseStream<parseFlags, Encoding, InputStream>(is);\n    }\n\n    //! Parse JSON text from an input stream (with \\ref kParseDefaultFlags)\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);\n    }\n    //!@}\n\n    //!@name Parse in-place from mutable string\n    //!@{\n\n    //! Parse JSON text from a mutable string\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\param str Mutable zero-terminated string to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags>\n    GenericDocument& ParseInsitu(Ch* str) {\n        GenericInsituStringStream<Encoding> s(str);\n        return ParseStream<parseFlags | kParseInsituFlag>(s);\n    }\n\n    //! Parse JSON text from a mutable string (with \\ref kParseDefaultFlags)\n    /*! \\param str Mutable zero-terminated string to be parsed.\n        \\return The document itself for fluent API.\n    */\n    GenericDocument& ParseInsitu(Ch* str) {\n        return ParseInsitu<kParseDefaultFlags>(str);\n    }\n    //!@}\n\n    //!@name Parse from read-only string\n    //!@{\n\n    //! Parse JSON text from a read-only string (with Encoding conversion)\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag (must not contain \\ref kParseInsituFlag).\n        \\tparam SourceEncoding Transcoding from input Encoding\n        \\param str Read-only zero-terminated string to be parsed.\n    */\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const typename SourceEncoding::Ch* str) {\n        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));\n        GenericStringStream<SourceEncoding> s(str);\n        return ParseStream<parseFlags, SourceEncoding>(s);\n    }\n\n    //! Parse JSON text from a read-only string\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag (must not contain \\ref kParseInsituFlag).\n        \\param str Read-only zero-terminated string to be parsed.\n    */\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const Ch* str) {\n        return Parse<parseFlags, Encoding>(str);\n    }\n\n    //! Parse JSON text from a read-only string (with \\ref kParseDefaultFlags)\n    /*! \\param str Read-only zero-terminated string to be parsed.\n    */\n    GenericDocument& Parse(const Ch* str) {\n        return Parse<kParseDefaultFlags>(str);\n    }\n\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {\n        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));\n        MemoryStream ms(reinterpret_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));\n        EncodedInputStream<SourceEncoding, MemoryStream> is(ms);\n        ParseStream<parseFlags, SourceEncoding>(is);\n        return *this;\n    }\n\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const Ch* str, size_t length) {\n        return Parse<parseFlags, Encoding>(str, length);\n    }\n    \n    GenericDocument& Parse(const Ch* str, size_t length) {\n        return Parse<kParseDefaultFlags>(str, length);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {\n        // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)\n        return Parse<parseFlags, SourceEncoding>(str.c_str());\n    }\n\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const std::basic_string<Ch>& str) {\n        return Parse<parseFlags, Encoding>(str.c_str());\n    }\n\n    GenericDocument& Parse(const std::basic_string<Ch>& str) {\n        return Parse<kParseDefaultFlags>(str);\n    }\n#endif // RAPIDJSON_HAS_STDSTRING    \n\n    //!@}\n\n    //!@name Handling parse errors\n    //!@{\n\n    //! Whether a parse error has occurred in the last parsing.\n    bool HasParseError() const { return parseResult_.IsError(); }\n\n    //! Get the \\ref ParseErrorCode of last parsing.\n    ParseErrorCode GetParseError() const { return parseResult_.Code(); }\n\n    //! Get the position of last parsing error in input, 0 otherwise.\n    size_t GetErrorOffset() const { return parseResult_.Offset(); }\n\n    //! Implicit conversion to get the last parse result\n#ifndef __clang // -Wdocumentation\n    /*! \\return \\ref ParseResult of the last parse operation\n\n        \\code\n          Document doc;\n          ParseResult ok = doc.Parse(json);\n          if (!ok)\n            printf( \"JSON parse error: %s (%u)\\n\", GetParseError_En(ok.Code()), ok.Offset());\n        \\endcode\n     */\n#endif\n    operator ParseResult() const { return parseResult_; }\n    //!@}\n\n    //! Get the allocator of this document.\n    Allocator& GetAllocator() {\n        RAPIDJSON_ASSERT(allocator_);\n        return *allocator_;\n    }\n\n    //! Get the capacity of stack in bytes.\n    size_t GetStackCapacity() const { return stack_.GetCapacity(); }\n\nprivate:\n    // clear stack on any exit from ParseStream, e.g. due to exception\n    struct ClearStackOnExit {\n        explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}\n        ~ClearStackOnExit() { d_.ClearStack(); }\n    private:\n        ClearStackOnExit(const ClearStackOnExit&);\n        ClearStackOnExit& operator=(const ClearStackOnExit&);\n        GenericDocument& d_;\n    };\n\n    // callers of the following private Handler functions\n    // template <typename,typename,typename> friend class GenericReader; // for parsing\n    template <typename, typename> friend class GenericValue; // for deep copying\n\npublic:\n    // Implementation of Handler\n    bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }\n    bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }\n    bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }\n\n    bool RawNumber(const Ch* str, SizeType length, bool copy) { \n        if (copy) \n            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());\n        else\n            new (stack_.template Push<ValueType>()) ValueType(str, length);\n        return true;\n    }\n\n    bool String(const Ch* str, SizeType length, bool copy) { \n        if (copy) \n            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());\n        else\n            new (stack_.template Push<ValueType>()) ValueType(str, length);\n        return true;\n    }\n\n    bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }\n    \n    bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }\n\n    bool EndObject(SizeType memberCount) {\n        typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);\n        stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());\n        return true;\n    }\n\n    bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }\n    \n    bool EndArray(SizeType elementCount) {\n        ValueType* elements = stack_.template Pop<ValueType>(elementCount);\n        stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());\n        return true;\n    }\n\nprivate:\n    //! Prohibit copying\n    GenericDocument(const GenericDocument&);\n    //! Prohibit assignment\n    GenericDocument& operator=(const GenericDocument&);\n\n    void ClearStack() {\n        if (Allocator::kNeedFree)\n            while (stack_.GetSize() > 0)    // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)\n                (stack_.template Pop<ValueType>(1))->~ValueType();\n        else\n            stack_.Clear();\n        stack_.ShrinkToFit();\n    }\n\n    void Destroy() {\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    static const size_t kDefaultStackCapacity = 1024;\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    internal::Stack<StackAllocator> stack_;\n    ParseResult parseResult_;\n};\n\n//! GenericDocument with UTF8 encoding\ntypedef GenericDocument<UTF8<> > Document;\n\n//! Helper class for accessing Value of array type.\n/*!\n    Instance of this helper class is obtained by \\c GenericValue::GetArray().\n    In addition to all APIs for array type, it provides range-based for loop if \\c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.\n*/\ntemplate <bool Const, typename ValueT>\nclass GenericArray {\npublic:\n    typedef GenericArray<true, ValueT> ConstArray;\n    typedef GenericArray<false, ValueT> Array;\n    typedef ValueT PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n    typedef ValueType* ValueIterator;  // This may be const or non-const iterator\n    typedef const ValueT* ConstValueIterator;\n    typedef typename ValueType::AllocatorType AllocatorType;\n    typedef typename ValueType::StringRefType StringRefType;\n\n    template <typename, typename>\n    friend class GenericValue;\n\n    GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}\n    GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }\n    ~GenericArray() {}\n\n    SizeType Size() const { return value_.Size(); }\n    SizeType Capacity() const { return value_.Capacity(); }\n    bool Empty() const { return value_.Empty(); }\n    void Clear() const { value_.Clear(); }\n    ValueType& operator[](SizeType index) const {  return value_[index]; }\n    ValueIterator Begin() const { return value_.Begin(); }\n    ValueIterator End() const { return value_.End(); }\n    GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }\n    GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n    GenericArray PopBack() const { value_.PopBack(); return *this; }\n    ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }\n    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }\n\n#if RAPIDJSON_HAS_CXX11_RANGE_FOR\n    ValueIterator begin() const { return value_.Begin(); }\n    ValueIterator end() const { return value_.End(); }\n#endif\n\nprivate:\n    GenericArray();\n    GenericArray(ValueType& value) : value_(value) {}\n    ValueType& value_;\n};\n\n//! Helper class for accessing Value of object type.\n/*!\n    Instance of this helper class is obtained by \\c GenericValue::GetObject().\n    In addition to all APIs for array type, it provides range-based for loop if \\c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.\n*/\ntemplate <bool Const, typename ValueT>\nclass GenericObject {\npublic:\n    typedef GenericObject<true, ValueT> ConstObject;\n    typedef GenericObject<false, ValueT> Object;\n    typedef ValueT PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n    typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator;  // This may be const or non-const iterator\n    typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;\n    typedef typename ValueType::AllocatorType AllocatorType;\n    typedef typename ValueType::StringRefType StringRefType;\n    typedef typename ValueType::EncodingType EncodingType;\n    typedef typename ValueType::Ch Ch;\n\n    template <typename, typename>\n    friend class GenericValue;\n\n    GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}\n    GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }\n    ~GenericObject() {}\n\n    SizeType MemberCount() const { return value_.MemberCount(); }\n    SizeType MemberCapacity() const { return value_.MemberCapacity(); }\n    bool ObjectEmpty() const { return value_.ObjectEmpty(); }\n    template <typename T> ValueType& operator[](T* name) const { return value_[name]; }\n    template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }\n#if RAPIDJSON_HAS_STDSTRING\n    ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }\n#endif\n    MemberIterator MemberBegin() const { return value_.MemberBegin(); }\n    MemberIterator MemberEnd() const { return value_.MemberEnd(); }\n    GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; }\n    bool HasMember(const Ch* name) const { return value_.HasMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }\n#endif\n    template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }\n    MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }\n    template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }\n#endif\n    GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#if RAPIDJSON_HAS_STDSTRING\n    GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#endif\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    void RemoveAllMembers() { value_.RemoveAllMembers(); }\n    bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }\n#endif\n    template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }\n    MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }\n    MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }\n    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }\n    bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }\n#endif\n    template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }\n\n#if RAPIDJSON_HAS_CXX11_RANGE_FOR\n    MemberIterator begin() const { return value_.MemberBegin(); }\n    MemberIterator end() const { return value_.MemberEnd(); }\n#endif\n\nprivate:\n    GenericObject();\n    GenericObject(ValueType& value) : value_(value) {}\n    ValueType& value_;\n};\n\nRAPIDJSON_NAMESPACE_END\nRAPIDJSON_DIAG_POP\n\n#endif // RAPIDJSON_DOCUMENT_H_\n"
  },
  {
    "path": "src/json/rapidjson/encodedstream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ENCODEDSTREAM_H_\n#define RAPIDJSON_ENCODEDSTREAM_H_\n\n#include \"stream.h\"\n#include \"memorystream.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Input byte stream wrapper with a statically bound encoding.\n/*!\n    \\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.\n    \\tparam InputByteStream Type of input byte stream. For example, FileReadStream.\n*/\ntemplate <typename Encoding, typename InputByteStream>\nclass EncodedInputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    EncodedInputStream(InputByteStream& is) : is_(is) { \n        current_ = Encoding::TakeBOM(is_);\n    }\n\n    Ch Peek() const { return current_; }\n    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }\n    size_t Tell() const { return is_.Tell(); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    EncodedInputStream(const EncodedInputStream&);\n    EncodedInputStream& operator=(const EncodedInputStream&);\n\n    InputByteStream& is_;\n    Ch current_;\n};\n\n//! Specialized for UTF8 MemoryStream.\ntemplate <>\nclass EncodedInputStream<UTF8<>, MemoryStream> {\npublic:\n    typedef UTF8<>::Ch Ch;\n\n    EncodedInputStream(MemoryStream& is) : is_(is) {\n        if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();\n        if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();\n        if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();\n    }\n    Ch Peek() const { return is_.Peek(); }\n    Ch Take() { return is_.Take(); }\n    size_t Tell() const { return is_.Tell(); }\n\n    // Not implemented\n    void Put(Ch) {}\n    void Flush() {} \n    Ch* PutBegin() { return 0; }\n    size_t PutEnd(Ch*) { return 0; }\n\n    MemoryStream& is_;\n\nprivate:\n    EncodedInputStream(const EncodedInputStream&);\n    EncodedInputStream& operator=(const EncodedInputStream&);\n};\n\n//! Output byte stream wrapper with statically bound encoding.\n/*!\n    \\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.\n    \\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.\n*/\ntemplate <typename Encoding, typename OutputByteStream>\nclass EncodedOutputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { \n        if (putBOM)\n            Encoding::PutBOM(os_);\n    }\n\n    void Put(Ch c) { Encoding::Put(os_, c);  }\n    void Flush() { os_.Flush(); }\n\n    // Not implemented\n    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}\n    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}\n    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    EncodedOutputStream(const EncodedOutputStream&);\n    EncodedOutputStream& operator=(const EncodedOutputStream&);\n\n    OutputByteStream& os_;\n};\n\n#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x\n\n//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.\n/*!\n    \\tparam CharType Type of character for reading.\n    \\tparam InputByteStream type of input byte stream to be wrapped.\n*/\ntemplate <typename CharType, typename InputByteStream>\nclass AutoUTFInputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\npublic:\n    typedef CharType Ch;\n\n    //! Constructor.\n    /*!\n        \\param is input stream to be wrapped.\n        \\param type UTF encoding type if it is not detected from the stream.\n    */\n    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {\n        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        \n        DetectType();\n        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };\n        takeFunc_ = f[type_];\n        current_ = takeFunc_(*is_);\n    }\n\n    UTFType GetType() const { return type_; }\n    bool HasBOM() const { return hasBOM_; }\n\n    Ch Peek() const { return current_; }\n    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }\n    size_t Tell() const { return is_->Tell(); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    AutoUTFInputStream(const AutoUTFInputStream&);\n    AutoUTFInputStream& operator=(const AutoUTFInputStream&);\n\n    // Detect encoding type with BOM or RFC 4627\n    void DetectType() {\n        // BOM (Byte Order Mark):\n        // 00 00 FE FF  UTF-32BE\n        // FF FE 00 00  UTF-32LE\n        // FE FF        UTF-16BE\n        // FF FE        UTF-16LE\n        // EF BB BF     UTF-8\n\n        const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());\n        if (!c)\n            return;\n\n        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));\n        hasBOM_ = false;\n        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }\n        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }\n        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }\n        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }\n        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }\n\n        // RFC 4627: Section 3\n        // \"Since the first two characters of a JSON text will always be ASCII\n        // characters [RFC0020], it is possible to determine whether an octet\n        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking\n        // at the pattern of nulls in the first four octets.\"\n        // 00 00 00 xx  UTF-32BE\n        // 00 xx 00 xx  UTF-16BE\n        // xx 00 00 00  UTF-32LE\n        // xx 00 xx 00  UTF-16LE\n        // xx xx xx xx  UTF-8\n\n        if (!hasBOM_) {\n            int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);\n            switch (pattern) {\n            case 0x08: type_ = kUTF32BE; break;\n            case 0x0A: type_ = kUTF16BE; break;\n            case 0x01: type_ = kUTF32LE; break;\n            case 0x05: type_ = kUTF16LE; break;\n            case 0x0F: type_ = kUTF8;    break;\n            default: break; // Use type defined by user.\n            }\n        }\n\n        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.\n        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);\n        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);\n    }\n\n    typedef Ch (*TakeFunc)(InputByteStream& is);\n    InputByteStream* is_;\n    UTFType type_;\n    Ch current_;\n    TakeFunc takeFunc_;\n    bool hasBOM_;\n};\n\n//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.\n/*!\n    \\tparam CharType Type of character for writing.\n    \\tparam OutputByteStream type of output byte stream to be wrapped.\n*/\ntemplate <typename CharType, typename OutputByteStream>\nclass AutoUTFOutputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\npublic:\n    typedef CharType Ch;\n\n    //! Constructor.\n    /*!\n        \\param os output stream to be wrapped.\n        \\param type UTF encoding type.\n        \\param putBOM Whether to write BOM at the beginning of the stream.\n    */\n    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {\n        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);\n\n        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.\n        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);\n        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);\n\n        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };\n        putFunc_ = f[type_];\n\n        if (putBOM)\n            PutBOM();\n    }\n\n    UTFType GetType() const { return type_; }\n\n    void Put(Ch c) { putFunc_(*os_, c); }\n    void Flush() { os_->Flush(); } \n\n    // Not implemented\n    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}\n    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    AutoUTFOutputStream(const AutoUTFOutputStream&);\n    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);\n\n    void PutBOM() { \n        typedef void (*PutBOMFunc)(OutputByteStream&);\n        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };\n        f[type_](*os_);\n    }\n\n    typedef void (*PutFunc)(OutputByteStream&, Ch);\n\n    OutputByteStream* os_;\n    UTFType type_;\n    PutFunc putFunc_;\n};\n\n#undef RAPIDJSON_ENCODINGS_FUNC\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "src/json/rapidjson/encodings.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ENCODINGS_H_\n#define RAPIDJSON_ENCODINGS_H_\n\n#include \"rapidjson.h\"\n\n#if defined(_MSC_VER) && !defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\n#elif defined(__GNUC__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\nRAPIDJSON_DIAG_OFF(overflow)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Encoding\n\n/*! \\class rapidjson::Encoding\n    \\brief Concept for encoding of Unicode characters.\n\n\\code\nconcept Encoding {\n    typename Ch;    //! Type of character. A \"character\" is actually a code unit in unicode's definition.\n\n    enum { supportUnicode = 1 }; // or 0 if not supporting unicode\n\n    //! \\brief Encode a Unicode codepoint to an output stream.\n    //! \\param os Output stream.\n    //! \\param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint);\n\n    //! \\brief Decode a Unicode codepoint from an input stream.\n    //! \\param is Input stream.\n    //! \\param codepoint Output of the unicode codepoint.\n    //! \\return true if a valid codepoint can be decoded from the stream.\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint);\n\n    //! \\brief Validate one Unicode codepoint from an encoded stream.\n    //! \\param is Input stream to obtain codepoint.\n    //! \\param os Output for copying one codepoint.\n    //! \\return true if it is valid.\n    //! \\note This function just validating and copying the codepoint without actually decode it.\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os);\n\n    // The following functions are deal with byte streams.\n\n    //! Take a character from input byte stream, skip BOM if exist.\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is);\n\n    //! Take a character from input byte stream.\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is);\n\n    //! Put BOM to output byte stream.\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os);\n\n    //! Put a character to output byte stream.\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF8\n\n//! UTF-8 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-8\n    http://tools.ietf.org/html/rfc3629\n    \\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.\n    \\note implements Encoding concept\n*/\ntemplate<typename CharType = char>\nstruct UTF8 {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        if (codepoint <= 0x7F) \n            os.Put(static_cast<Ch>(codepoint & 0xFF));\n        else if (codepoint <= 0x7FF) {\n            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));\n        }\n        else if (codepoint <= 0xFFFF) {\n            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n    }\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        if (codepoint <= 0x7F) \n            PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));\n        else if (codepoint <= 0x7FF) {\n            PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));\n        }\n        else if (codepoint <= 0xFFFF) {\n            PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)\n#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)\n#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)\n        typename InputStream::Ch c = is.Take();\n        if (!(c & 0x80)) {\n            *codepoint = static_cast<unsigned char>(c);\n            return true;\n        }\n\n        unsigned char type = GetRange(static_cast<unsigned char>(c));\n        if (type >= 32) {\n            *codepoint = 0;\n        } else {\n            *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);\n        }\n        bool result = true;\n        switch (type) {\n        case 2: RAPIDJSON_TAIL(); return result;\n        case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;\n        case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;\n        case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        default: return false;\n        }\n#undef RAPIDJSON_COPY\n#undef RAPIDJSON_TRANS\n#undef RAPIDJSON_TAIL\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n#define RAPIDJSON_COPY() os.Put(c = is.Take())\n#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)\n#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)\n        Ch c;\n        RAPIDJSON_COPY();\n        if (!(c & 0x80))\n            return true;\n\n        bool result = true;\n        switch (GetRange(static_cast<unsigned char>(c))) {\n        case 2: RAPIDJSON_TAIL(); return result;\n        case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;\n        case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;\n        case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;\n        default: return false;\n        }\n#undef RAPIDJSON_COPY\n#undef RAPIDJSON_TRANS\n#undef RAPIDJSON_TAIL\n    }\n\n    static unsigned char GetRange(unsigned char c) {\n        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.\n        static const unsigned char type[] = {\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,\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,\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,\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,\n            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,\n            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,\n            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,\n            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,\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,\n            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,\n        };\n        return type[c];\n    }\n\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        typename InputByteStream::Ch c = Take(is);\n        if (static_cast<unsigned char>(c) != 0xEFu) return c;\n        c = is.Take();\n        if (static_cast<unsigned char>(c) != 0xBBu) return c;\n        c = is.Take();\n        if (static_cast<unsigned char>(c) != 0xBFu) return c;\n        c = is.Take();\n        return c;\n    }\n\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        return static_cast<Ch>(is.Take());\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF16\n\n//! UTF-16 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-16\n    http://tools.ietf.org/html/rfc2781\n    \\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.\n    \\note implements Encoding concept\n\n    \\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.\n    For streaming, use UTF16LE and UTF16BE, which handle endianness.\n*/\ntemplate<typename CharType = wchar_t>\nstruct UTF16 {\n    typedef CharType Ch;\n    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        if (codepoint <= 0xFFFF) {\n            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair \n            os.Put(static_cast<typename OutputStream::Ch>(codepoint));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            unsigned v = codepoint - 0x10000;\n            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));\n            os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));\n        }\n    }\n\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        if (codepoint <= 0xFFFF) {\n            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair \n            PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            unsigned v = codepoint - 0x10000;\n            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));\n            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));\n        }\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);\n        typename InputStream::Ch c = is.Take();\n        if (c < 0xD800 || c > 0xDFFF) {\n            *codepoint = static_cast<unsigned>(c);\n            return true;\n        }\n        else if (c <= 0xDBFF) {\n            *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;\n            c = is.Take();\n            *codepoint |= (static_cast<unsigned>(c) & 0x3FF);\n            *codepoint += 0x10000;\n            return c >= 0xDC00 && c <= 0xDFFF;\n        }\n        return false;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        typename InputStream::Ch c;\n        os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));\n        if (c < 0xD800 || c > 0xDFFF)\n            return true;\n        else if (c <= 0xDBFF) {\n            os.Put(c = is.Take());\n            return c >= 0xDC00 && c <= 0xDFFF;\n        }\n        return false;\n    }\n};\n\n//! UTF-16 little endian encoding.\ntemplate<typename CharType = wchar_t>\nstruct UTF16LE : UTF16<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<uint8_t>(is.Take());\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));\n    }\n};\n\n//! UTF-16 big endian encoding.\ntemplate<typename CharType = wchar_t>\nstruct UTF16BE : UTF16<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF32\n\n//! UTF-32 encoding. \n/*! http://en.wikipedia.org/wiki/UTF-32\n    \\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.\n    \\note implements Encoding concept\n\n    \\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.\n    For streaming, use UTF32LE and UTF32BE, which handle endianness.\n*/\ntemplate<typename CharType = unsigned>\nstruct UTF32 {\n    typedef CharType Ch;\n    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);\n        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n        os.Put(codepoint);\n    }\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);\n        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n        PutUnsafe(os, codepoint);\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);\n        Ch c = is.Take();\n        *codepoint = c;\n        return c <= 0x10FFFF;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);\n        Ch c;\n        os.Put(c = is.Take());\n        return c <= 0x10FFFF;\n    }\n};\n\n//! UTF-32 little endian enocoding.\ntemplate<typename CharType = unsigned>\nstruct UTF32LE : UTF32<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<uint8_t>(is.Take());\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));\n    }\n};\n\n//! UTF-32 big endian encoding.\ntemplate<typename CharType = unsigned>\nstruct UTF32BE : UTF32<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; \n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// ASCII\n\n//! ASCII encoding.\n/*! http://en.wikipedia.org/wiki/ASCII\n    \\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.\n    \\note implements Encoding concept\n*/\ntemplate<typename CharType = char>\nstruct ASCII {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 0 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_ASSERT(codepoint <= 0x7F);\n        os.Put(static_cast<Ch>(codepoint & 0xFF));\n    }\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_ASSERT(codepoint <= 0x7F);\n        PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        uint8_t c = static_cast<uint8_t>(is.Take());\n        *codepoint = c;\n        return c <= 0X7F;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        uint8_t c = static_cast<uint8_t>(is.Take());\n        os.Put(static_cast<typename OutputStream::Ch>(c));\n        return c <= 0x7F;\n    }\n\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        uint8_t c = static_cast<uint8_t>(Take(is));\n        return static_cast<Ch>(c);\n    }\n\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        return static_cast<Ch>(is.Take());\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        (void)os;\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// AutoUTF\n\n//! Runtime-specified UTF encoding type of a stream.\nenum UTFType {\n    kUTF8 = 0,      //!< UTF-8.\n    kUTF16LE = 1,   //!< UTF-16 little endian.\n    kUTF16BE = 2,   //!< UTF-16 big endian.\n    kUTF32LE = 3,   //!< UTF-32 little endian.\n    kUTF32BE = 4    //!< UTF-32 big endian.\n};\n\n//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.\n/*! \\note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().\n*/\ntemplate<typename CharType>\nstruct AutoUTF {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 1 };\n\n#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x\n\n    template<typename OutputStream>\n    static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {\n        typedef void (*EncodeFunc)(OutputStream&, unsigned);\n        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };\n        (*f[os.GetType()])(os, codepoint);\n    }\n\n    template<typename OutputStream>\n    static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        typedef void (*EncodeFunc)(OutputStream&, unsigned);\n        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };\n        (*f[os.GetType()])(os, codepoint);\n    }\n\n    template <typename InputStream>\n    static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {\n        typedef bool (*DecodeFunc)(InputStream&, unsigned*);\n        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };\n        return (*f[is.GetType()])(is, codepoint);\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {\n        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);\n        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };\n        return (*f[is.GetType()])(is, os);\n    }\n\n#undef RAPIDJSON_ENCODINGS_FUNC\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Transcoder\n\n//! Encoding conversion.\ntemplate<typename SourceEncoding, typename TargetEncoding>\nstruct Transcoder {\n    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.\n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {\n        unsigned codepoint;\n        if (!SourceEncoding::Decode(is, &codepoint))\n            return false;\n        TargetEncoding::Encode(os, codepoint);\n        return true;\n    }\n\n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {\n        unsigned codepoint;\n        if (!SourceEncoding::Decode(is, &codepoint))\n            return false;\n        TargetEncoding::EncodeUnsafe(os, codepoint);\n        return true;\n    }\n\n    //! Validate one Unicode codepoint from an encoded stream.\n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {\n        return Transcode(is, os);   // Since source/target encoding is different, must transcode.\n    }\n};\n\n// Forward declaration.\ntemplate<typename Stream>\ninline void PutUnsafe(Stream& stream, typename Stream::Ch c);\n\n//! Specialization of Transcoder with same source and target encoding.\ntemplate<typename Encoding>\nstruct Transcoder<Encoding, Encoding> {\n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {\n        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.\n        return true;\n    }\n    \n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {\n        PutUnsafe(os, is.Take());  // Just copy one code unit. This semantic is different from primary template class.\n        return true;\n    }\n    \n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {\n        return Encoding::Validate(is, os);  // source/target encoding are the same\n    }\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ENCODINGS_H_\n"
  },
  {
    "path": "src/json/rapidjson/error/en.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ERROR_EN_H_\n#define RAPIDJSON_ERROR_EN_H_\n\n#include \"error.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(switch-enum)\nRAPIDJSON_DIAG_OFF(covered-switch-default)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Maps error code of parsing into error message.\n/*!\n    \\ingroup RAPIDJSON_ERRORS\n    \\param parseErrorCode Error code obtained in parsing.\n    \\return the error message.\n    \\note User can make a copy of this function for localization.\n        Using switch-case is safer for future modification of error codes.\n*/\ninline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {\n    switch (parseErrorCode) {\n        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING(\"No error.\");\n\n        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING(\"The document is empty.\");\n        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING(\"The document root must not be followed by other values.\");\n    \n        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING(\"Invalid value.\");\n    \n        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING(\"Missing a name for object member.\");\n        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING(\"Missing a colon after a name of object member.\");\n        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING(\"Missing a comma or '}' after an object member.\");\n    \n        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING(\"Missing a comma or ']' after an array element.\");\n\n        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING(\"Incorrect hex digit after \\\\u escape in string.\");\n        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING(\"The surrogate pair in string is invalid.\");\n        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING(\"Invalid escape character in string.\");\n        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING(\"Missing a closing quotation mark in string.\");\n        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING(\"Invalid encoding in string.\");\n\n        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING(\"Number too big to be stored in double.\");\n        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING(\"Miss fraction part in number.\");\n        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING(\"Miss exponent in number.\");\n\n        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING(\"Terminate parsing due to Handler error.\");\n        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING(\"Unspecific syntax error.\");\n\n        default:                                        return RAPIDJSON_ERROR_STRING(\"Unknown error.\");\n    }\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ERROR_EN_H_\n"
  },
  {
    "path": "src/json/rapidjson/error/error.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ERROR_ERROR_H_\n#define RAPIDJSON_ERROR_ERROR_H_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\n/*! \\file error.h */\n\n/*! \\defgroup RAPIDJSON_ERRORS RapidJSON error handling */\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ERROR_CHARTYPE\n\n//! Character type of error messages.\n/*! \\ingroup RAPIDJSON_ERRORS\n    The default character type is \\c char.\n    On Windows, user can define this macro as \\c TCHAR for supporting both\n    unicode/non-unicode settings.\n*/\n#ifndef RAPIDJSON_ERROR_CHARTYPE\n#define RAPIDJSON_ERROR_CHARTYPE char\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ERROR_STRING\n\n//! Macro for converting string literial to \\ref RAPIDJSON_ERROR_CHARTYPE[].\n/*! \\ingroup RAPIDJSON_ERRORS\n    By default this conversion macro does nothing.\n    On Windows, user can define this macro as \\c _T(x) for supporting both\n    unicode/non-unicode settings.\n*/\n#ifndef RAPIDJSON_ERROR_STRING\n#define RAPIDJSON_ERROR_STRING(x) x\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseErrorCode\n\n//! Error code of parsing.\n/*! \\ingroup RAPIDJSON_ERRORS\n    \\see GenericReader::Parse, GenericReader::GetParseErrorCode\n*/\nenum ParseErrorCode {\n    kParseErrorNone = 0,                        //!< No error.\n\n    kParseErrorDocumentEmpty,                   //!< The document is empty.\n    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.\n\n    kParseErrorValueInvalid,                    //!< Invalid value.\n\n    kParseErrorObjectMissName,                  //!< Missing a name for object member.\n    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.\n    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.\n\n    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.\n\n    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\\\u escape in string.\n    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.\n    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.\n    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.\n    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.\n\n    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.\n    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.\n    kParseErrorNumberMissExponent,              //!< Miss exponent in number.\n\n    kParseErrorTermination,                     //!< Parsing was terminated.\n    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.\n};\n\n//! Result of parsing (wraps ParseErrorCode)\n/*!\n    \\ingroup RAPIDJSON_ERRORS\n    \\code\n        Document doc;\n        ParseResult ok = doc.Parse(\"[42]\");\n        if (!ok) {\n            fprintf(stderr, \"JSON parse error: %s (%u)\",\n                    GetParseError_En(ok.Code()), ok.Offset());\n            exit(EXIT_FAILURE);\n        }\n    \\endcode\n    \\see GenericReader::Parse, GenericDocument::Parse\n*/\nstruct ParseResult {\n    //!! Unspecified boolean type\n    typedef bool (ParseResult::*BooleanType)() const;\npublic:\n    //! Default constructor, no error.\n    ParseResult() : code_(kParseErrorNone), offset_(0) {}\n    //! Constructor to set an error.\n    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}\n\n    //! Get the error code.\n    ParseErrorCode Code() const { return code_; }\n    //! Get the error offset, if \\ref IsError(), 0 otherwise.\n    size_t Offset() const { return offset_; }\n\n    //! Explicit conversion to \\c bool, returns \\c true, iff !\\ref IsError().\n    operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }\n    //! Whether the result is an error.\n    bool IsError() const { return code_ != kParseErrorNone; }\n\n    bool operator==(const ParseResult& that) const { return code_ == that.code_; }\n    bool operator==(ParseErrorCode code) const { return code_ == code; }\n    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }\n\n    bool operator!=(const ParseResult& that) const { return !(*this == that); }\n    bool operator!=(ParseErrorCode code) const { return !(*this == code); }\n    friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }\n\n    //! Reset error code.\n    void Clear() { Set(kParseErrorNone); }\n    //! Update error code and offset.\n    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }\n\nprivate:\n    ParseErrorCode code_;\n    size_t offset_;\n};\n\n//! Function pointer type of GetParseError().\n/*! \\ingroup RAPIDJSON_ERRORS\n\n    This is the prototype for \\c GetParseError_X(), where \\c X is a locale.\n    User can dynamically change locale in runtime, e.g.:\n\\code\n    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever\n    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());\n\\endcode\n*/\ntypedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ERROR_ERROR_H_\n"
  },
  {
    "path": "src/json/rapidjson/filereadstream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FILEREADSTREAM_H_\n#define RAPIDJSON_FILEREADSTREAM_H_\n\n#include \"stream.h\"\n#include <cstdio>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(unreachable-code)\nRAPIDJSON_DIAG_OFF(missing-noreturn)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! File byte stream for input using fread().\n/*!\n    \\note implements Stream concept\n*/\nclass FileReadStream {\npublic:\n    typedef char Ch;    //!< Character type (byte).\n\n    //! Constructor.\n    /*!\n        \\param fp File pointer opened for read.\n        \\param buffer user-supplied buffer.\n        \\param bufferSize size of buffer in bytes. Must >=4 bytes.\n    */\n    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { \n        RAPIDJSON_ASSERT(fp_ != 0);\n        RAPIDJSON_ASSERT(bufferSize >= 4);\n        Read();\n    }\n\n    Ch Peek() const { return *current_; }\n    Ch Take() { Ch c = *current_; Read(); return c; }\n    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;\n    }\n\nprivate:\n    void Read() {\n        if (current_ < bufferLast_)\n            ++current_;\n        else if (!eof_) {\n            count_ += readCount_;\n            readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);\n            bufferLast_ = buffer_ + readCount_ - 1;\n            current_ = buffer_;\n\n            if (readCount_ < bufferSize_) {\n                buffer_[readCount_] = '\\0';\n                ++bufferLast_;\n                eof_ = true;\n            }\n        }\n    }\n\n    std::FILE* fp_;\n    Ch *buffer_;\n    size_t bufferSize_;\n    Ch *bufferLast_;\n    Ch *current_;\n    size_t readCount_;\n    size_t count_;  //!< Number of characters read\n    bool eof_;\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "src/json/rapidjson/filewritestream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FILEWRITESTREAM_H_\n#define RAPIDJSON_FILEWRITESTREAM_H_\n\n#include \"stream.h\"\n#include <cstdio>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(unreachable-code)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of C file stream for output using fwrite().\n/*!\n    \\note implements Stream concept\n*/\nclass FileWriteStream {\npublic:\n    typedef char Ch;    //!< Character type. Only support char.\n\n    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { \n        RAPIDJSON_ASSERT(fp_ != 0);\n    }\n\n    void Put(char c) { \n        if (current_ >= bufferEnd_)\n            Flush();\n\n        *current_++ = c;\n    }\n\n    void PutN(char c, size_t n) {\n        size_t avail = static_cast<size_t>(bufferEnd_ - current_);\n        while (n > avail) {\n            std::memset(current_, c, avail);\n            current_ += avail;\n            Flush();\n            n -= avail;\n            avail = static_cast<size_t>(bufferEnd_ - current_);\n        }\n\n        if (n > 0) {\n            std::memset(current_, c, n);\n            current_ += n;\n        }\n    }\n\n    void Flush() {\n        if (current_ != buffer_) {\n            size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);\n            if (result < static_cast<size_t>(current_ - buffer_)) {\n                // failure deliberately ignored at this time\n                // added to avoid warn_unused_result build errors\n            }\n            current_ = buffer_;\n        }\n    }\n\n    // Not implemented\n    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }\n    char Take() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    FileWriteStream(const FileWriteStream&);\n    FileWriteStream& operator=(const FileWriteStream&);\n\n    std::FILE* fp_;\n    char *buffer_;\n    char *bufferEnd_;\n    char *current_;\n};\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(FileWriteStream& stream, char c, size_t n) {\n    stream.PutN(c, n);\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "src/json/rapidjson/fwd.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FWD_H_\n#define RAPIDJSON_FWD_H_\n\n#include \"rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n// encodings.h\n\ntemplate<typename CharType> struct UTF8;\ntemplate<typename CharType> struct UTF16;\ntemplate<typename CharType> struct UTF16BE;\ntemplate<typename CharType> struct UTF16LE;\ntemplate<typename CharType> struct UTF32;\ntemplate<typename CharType> struct UTF32BE;\ntemplate<typename CharType> struct UTF32LE;\ntemplate<typename CharType> struct ASCII;\ntemplate<typename CharType> struct AutoUTF;\n\ntemplate<typename SourceEncoding, typename TargetEncoding>\nstruct Transcoder;\n\n// allocators.h\n\nclass CrtAllocator;\n\ntemplate <typename BaseAllocator>\nclass MemoryPoolAllocator;\n\n// stream.h\n\ntemplate <typename Encoding>\nstruct GenericStringStream;\n\ntypedef GenericStringStream<UTF8<char> > StringStream;\n\ntemplate <typename Encoding>\nstruct GenericInsituStringStream;\n\ntypedef GenericInsituStringStream<UTF8<char> > InsituStringStream;\n\n// stringbuffer.h\n\ntemplate <typename Encoding, typename Allocator>\nclass GenericStringBuffer;\n\ntypedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;\n\n// filereadstream.h\n\nclass FileReadStream;\n\n// filewritestream.h\n\nclass FileWriteStream;\n\n// memorybuffer.h\n\ntemplate <typename Allocator>\nstruct GenericMemoryBuffer;\n\ntypedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;\n\n// memorystream.h\n\nstruct MemoryStream;\n\n// reader.h\n\ntemplate<typename Encoding, typename Derived>\nstruct BaseReaderHandler;\n\ntemplate <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>\nclass GenericReader;\n\ntypedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;\n\n// writer.h\n\ntemplate<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>\nclass Writer;\n\n// prettywriter.h\n\ntemplate<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>\nclass PrettyWriter;\n\n// document.h\n\ntemplate <typename Encoding, typename Allocator> \nstruct GenericMember;\n\ntemplate <bool Const, typename Encoding, typename Allocator>\nclass GenericMemberIterator;\n\ntemplate<typename CharType>\nstruct GenericStringRef;\n\ntemplate <typename Encoding, typename Allocator> \nclass GenericValue;\n\ntypedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;\n\ntemplate <typename Encoding, typename Allocator, typename StackAllocator>\nclass GenericDocument;\n\ntypedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;\n\n// pointer.h\n\ntemplate <typename ValueType, typename Allocator>\nclass GenericPointer;\n\ntypedef GenericPointer<Value, CrtAllocator> Pointer;\n\n// schema.h\n\ntemplate <typename SchemaDocumentType>\nclass IGenericRemoteSchemaDocumentProvider;\n\ntemplate <typename ValueT, typename Allocator>\nclass GenericSchemaDocument;\n\ntypedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;\ntypedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;\n\ntemplate <\n    typename SchemaDocumentType,\n    typename OutputHandler,\n    typename StateAllocator>\nclass GenericSchemaValidator;\n\ntypedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_RAPIDJSONFWD_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/biginteger.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_BIGINTEGER_H_\n#define RAPIDJSON_BIGINTEGER_H_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\n#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)\n#include <intrin.h> // for _umul128\n#pragma intrinsic(_umul128)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\nclass BigInteger {\npublic:\n    typedef uint64_t Type;\n\n    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {\n        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));\n    }\n\n    explicit BigInteger(uint64_t u) : count_(1) {\n        digits_[0] = u;\n    }\n\n    BigInteger(const char* decimals, size_t length) : count_(1) {\n        RAPIDJSON_ASSERT(length > 0);\n        digits_[0] = 0;\n        size_t i = 0;\n        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19\n        while (length >= kMaxDigitPerIteration) {\n            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);\n            length -= kMaxDigitPerIteration;\n            i += kMaxDigitPerIteration;\n        }\n\n        if (length > 0)\n            AppendDecimal64(decimals + i, decimals + i + length);\n    }\n    \n    BigInteger& operator=(const BigInteger &rhs)\n    {\n        if (this != &rhs) {\n            count_ = rhs.count_;\n            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));\n        }\n        return *this;\n    }\n    \n    BigInteger& operator=(uint64_t u) {\n        digits_[0] = u;            \n        count_ = 1;\n        return *this;\n    }\n\n    BigInteger& operator+=(uint64_t u) {\n        Type backup = digits_[0];\n        digits_[0] += u;\n        for (size_t i = 0; i < count_ - 1; i++) {\n            if (digits_[i] >= backup)\n                return *this; // no carry\n            backup = digits_[i + 1];\n            digits_[i + 1] += 1;\n        }\n\n        // Last carry\n        if (digits_[count_ - 1] < backup)\n            PushBack(1);\n\n        return *this;\n    }\n\n    BigInteger& operator*=(uint64_t u) {\n        if (u == 0) return *this = 0;\n        if (u == 1) return *this;\n        if (*this == 1) return *this = u;\n\n        uint64_t k = 0;\n        for (size_t i = 0; i < count_; i++) {\n            uint64_t hi;\n            digits_[i] = MulAdd64(digits_[i], u, k, &hi);\n            k = hi;\n        }\n        \n        if (k > 0)\n            PushBack(k);\n\n        return *this;\n    }\n\n    BigInteger& operator*=(uint32_t u) {\n        if (u == 0) return *this = 0;\n        if (u == 1) return *this;\n        if (*this == 1) return *this = u;\n\n        uint64_t k = 0;\n        for (size_t i = 0; i < count_; i++) {\n            const uint64_t c = digits_[i] >> 32;\n            const uint64_t d = digits_[i] & 0xFFFFFFFF;\n            const uint64_t uc = u * c;\n            const uint64_t ud = u * d;\n            const uint64_t p0 = ud + k;\n            const uint64_t p1 = uc + (p0 >> 32);\n            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);\n            k = p1 >> 32;\n        }\n        \n        if (k > 0)\n            PushBack(k);\n\n        return *this;\n    }\n\n    BigInteger& operator<<=(size_t shift) {\n        if (IsZero() || shift == 0) return *this;\n\n        size_t offset = shift / kTypeBit;\n        size_t interShift = shift % kTypeBit;\n        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);\n\n        if (interShift == 0) {\n            std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));\n            count_ += offset;\n        }\n        else {\n            digits_[count_] = 0;\n            for (size_t i = count_; i > 0; i--)\n                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));\n            digits_[offset] = digits_[0] << interShift;\n            count_ += offset;\n            if (digits_[count_])\n                count_++;\n        }\n\n        std::memset(digits_, 0, offset * sizeof(Type));\n\n        return *this;\n    }\n\n    bool operator==(const BigInteger& rhs) const {\n        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;\n    }\n\n    bool operator==(const Type rhs) const {\n        return count_ == 1 && digits_[0] == rhs;\n    }\n\n    BigInteger& MultiplyPow5(unsigned exp) {\n        static const uint32_t kPow5[12] = {\n            5,\n            5 * 5,\n            5 * 5 * 5,\n            5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5\n        };\n        if (exp == 0) return *this;\n        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27\n        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13\n        if (exp > 0)                 *this *= kPow5[exp - 1];\n        return *this;\n    }\n\n    // Compute absolute difference of this and rhs.\n    // Assume this != rhs\n    bool Difference(const BigInteger& rhs, BigInteger* out) const {\n        int cmp = Compare(rhs);\n        RAPIDJSON_ASSERT(cmp != 0);\n        const BigInteger *a, *b;  // Makes a > b\n        bool ret;\n        if (cmp < 0) { a = &rhs; b = this; ret = true; }\n        else         { a = this; b = &rhs; ret = false; }\n\n        Type borrow = 0;\n        for (size_t i = 0; i < a->count_; i++) {\n            Type d = a->digits_[i] - borrow;\n            if (i < b->count_)\n                d -= b->digits_[i];\n            borrow = (d > a->digits_[i]) ? 1 : 0;\n            out->digits_[i] = d;\n            if (d != 0)\n                out->count_ = i + 1;\n        }\n\n        return ret;\n    }\n\n    int Compare(const BigInteger& rhs) const {\n        if (count_ != rhs.count_)\n            return count_ < rhs.count_ ? -1 : 1;\n\n        for (size_t i = count_; i-- > 0;)\n            if (digits_[i] != rhs.digits_[i])\n                return digits_[i] < rhs.digits_[i] ? -1 : 1;\n\n        return 0;\n    }\n\n    size_t GetCount() const { return count_; }\n    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }\n    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }\n\nprivate:\n    void AppendDecimal64(const char* begin, const char* end) {\n        uint64_t u = ParseUint64(begin, end);\n        if (IsZero())\n            *this = u;\n        else {\n            unsigned exp = static_cast<unsigned>(end - begin);\n            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u\n        }\n    }\n\n    void PushBack(Type digit) {\n        RAPIDJSON_ASSERT(count_ < kCapacity);\n        digits_[count_++] = digit;\n    }\n\n    static uint64_t ParseUint64(const char* begin, const char* end) {\n        uint64_t r = 0;\n        for (const char* p = begin; p != end; ++p) {\n            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');\n            r = r * 10u + static_cast<unsigned>(*p - '0');\n        }\n        return r;\n    }\n\n    // Assume a * b + k < 2^128\n    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        uint64_t low = _umul128(a, b, outHigh) + k;\n        if (low < k)\n            (*outHigh)++;\n        return low;\n#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)\n        __extension__ typedef unsigned __int128 uint128;\n        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);\n        p += k;\n        *outHigh = static_cast<uint64_t>(p >> 64);\n        return static_cast<uint64_t>(p);\n#else\n        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;\n        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;\n        x1 += (x0 >> 32); // can't give carry\n        x1 += x2;\n        if (x1 < x2)\n            x3 += (static_cast<uint64_t>(1) << 32);\n        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);\n        uint64_t hi = x3 + (x1 >> 32);\n\n        lo += k;\n        if (lo < k)\n            hi++;\n        *outHigh = hi;\n        return lo;\n#endif\n    }\n\n    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000\n    static const size_t kCapacity = kBitCount / sizeof(Type);\n    static const size_t kTypeBit = sizeof(Type) * 8;\n\n    Type digits_[kCapacity];\n    size_t count_;\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_BIGINTEGER_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/diyfp.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n// This is a C++ header-only implementation of Grisu2 algorithm from the publication:\n// Loitsch, Florian. \"Printing floating-point numbers quickly and accurately with\n// integers.\" ACM Sigplan Notices 45.6 (2010): 233-243.\n\n#ifndef RAPIDJSON_DIYFP_H_\n#define RAPIDJSON_DIYFP_H_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n#include <limits>\n\n#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)\n#include <intrin.h>\n#pragma intrinsic(_BitScanReverse64)\n#pragma intrinsic(_umul128)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\nstruct DiyFp {\n    DiyFp() : f(), e() {}\n\n    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}\n\n    explicit DiyFp(double d) {\n        union {\n            double d;\n            uint64_t u64;\n        } u = { d };\n\n        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);\n        uint64_t significand = (u.u64 & kDpSignificandMask);\n        if (biased_e != 0) {\n            f = significand + kDpHiddenBit;\n            e = biased_e - kDpExponentBias;\n        }\n        else {\n            f = significand;\n            e = kDpMinExponent + 1;\n        }\n    }\n\n    DiyFp operator-(const DiyFp& rhs) const {\n        return DiyFp(f - rhs.f, e);\n    }\n\n    DiyFp operator*(const DiyFp& rhs) const {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        uint64_t h;\n        uint64_t l = _umul128(f, rhs.f, &h);\n        if (l & (uint64_t(1) << 63)) // rounding\n            h++;\n        return DiyFp(h, e + rhs.e + 64);\n#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)\n        __extension__ typedef unsigned __int128 uint128;\n        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);\n        uint64_t h = static_cast<uint64_t>(p >> 64);\n        uint64_t l = static_cast<uint64_t>(p);\n        if (l & (uint64_t(1) << 63)) // rounding\n            h++;\n        return DiyFp(h, e + rhs.e + 64);\n#else\n        const uint64_t M32 = 0xFFFFFFFF;\n        const uint64_t a = f >> 32;\n        const uint64_t b = f & M32;\n        const uint64_t c = rhs.f >> 32;\n        const uint64_t d = rhs.f & M32;\n        const uint64_t ac = a * c;\n        const uint64_t bc = b * c;\n        const uint64_t ad = a * d;\n        const uint64_t bd = b * d;\n        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);\n        tmp += 1U << 31;  /// mult_round\n        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);\n#endif\n    }\n\n    DiyFp Normalize() const {\n        RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        unsigned long index;\n        _BitScanReverse64(&index, f);\n        return DiyFp(f << (63 - index), e - (63 - index));\n#elif defined(__GNUC__) && __GNUC__ >= 4\n        int s = __builtin_clzll(f);\n        return DiyFp(f << s, e - s);\n#else\n        DiyFp res = *this;\n        while (!(res.f & (static_cast<uint64_t>(1) << 63))) {\n            res.f <<= 1;\n            res.e--;\n        }\n        return res;\n#endif\n    }\n\n    DiyFp NormalizeBoundary() const {\n        DiyFp res = *this;\n        while (!(res.f & (kDpHiddenBit << 1))) {\n            res.f <<= 1;\n            res.e--;\n        }\n        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);\n        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);\n        return res;\n    }\n\n    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {\n        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();\n        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);\n        mi.f <<= mi.e - pl.e;\n        mi.e = pl.e;\n        *plus = pl;\n        *minus = mi;\n    }\n\n    double ToDouble() const {\n        union {\n            double d;\n            uint64_t u64;\n        }u;\n        RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);\n        if (e < kDpDenormalExponent) {\n            // Underflow.\n            return 0.0;\n        }\n        if (e >= kDpMaxExponent) {\n            // Overflow.\n            return std::numeric_limits<double>::infinity();\n        }\n        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :\n            static_cast<uint64_t>(e + kDpExponentBias);\n        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);\n        return u.d;\n    }\n\n    static const int kDiySignificandSize = 64;\n    static const int kDpSignificandSize = 52;\n    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;\n    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;\n    static const int kDpMinExponent = -kDpExponentBias;\n    static const int kDpDenormalExponent = -kDpExponentBias + 1;\n    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);\n    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);\n    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);\n\n    uint64_t f;\n    int e;\n};\n\ninline DiyFp GetCachedPowerByIndex(size_t index) {\n    // 10^-348, 10^-340, ..., 10^340\n    static const uint64_t kCachedPowers_F[] = {\n        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),\n        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),\n        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),\n        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),\n        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),\n        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),\n        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),\n        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),\n        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),\n        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),\n        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),\n        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),\n        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),\n        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),\n        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),\n        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),\n        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),\n        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),\n        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),\n        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),\n        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),\n        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),\n        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),\n        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),\n        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),\n        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),\n        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),\n        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),\n        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),\n        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),\n        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),\n        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),\n        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),\n        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),\n        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),\n        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),\n        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),\n        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),\n        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),\n        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),\n        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),\n        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),\n        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),\n        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)\n    };\n    static const int16_t kCachedPowers_E[] = {\n        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,\n        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,\n        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,\n        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,\n        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,\n        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,\n        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,\n        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,\n        907,   933,   960,   986,  1013,  1039,  1066\n    };\n    RAPIDJSON_ASSERT(index < 87);\n    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);\n}\n\ninline DiyFp GetCachedPower(int e, int* K) {\n\n    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;\n    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive\n    int k = static_cast<int>(dk);\n    if (dk - k > 0.0)\n        k++;\n\n    unsigned index = static_cast<unsigned>((k >> 3) + 1);\n    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table\n\n    return GetCachedPowerByIndex(index);\n}\n\ninline DiyFp GetCachedPower10(int exp, int *outExp) {\n    RAPIDJSON_ASSERT(exp >= -348);\n    unsigned index = static_cast<unsigned>(exp + 348) / 8u;\n    *outExp = -348 + static_cast<int>(index) * 8;\n    return GetCachedPowerByIndex(index);\n}\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_DIYFP_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/dtoa.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n// This is a C++ header-only implementation of Grisu2 algorithm from the publication:\n// Loitsch, Florian. \"Printing floating-point numbers quickly and accurately with\n// integers.\" ACM Sigplan Notices 45.6 (2010): 233-243.\n\n#ifndef RAPIDJSON_DTOA_\n#define RAPIDJSON_DTOA_\n\n#include \"itoa.h\" // GetDigitsLut()\n#include \"diyfp.h\"\n#include \"ieee754.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\nRAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124\n#endif\n\ninline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {\n    while (rest < wp_w && delta - rest >= ten_kappa &&\n           (rest + ten_kappa < wp_w ||  /// closer\n            wp_w - rest > rest + ten_kappa - wp_w)) {\n        buffer[len - 1]--;\n        rest += ten_kappa;\n    }\n}\n\ninline int CountDecimalDigit32(uint32_t n) {\n    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.\n    if (n < 10) return 1;\n    if (n < 100) return 2;\n    if (n < 1000) return 3;\n    if (n < 10000) return 4;\n    if (n < 100000) return 5;\n    if (n < 1000000) return 6;\n    if (n < 10000000) return 7;\n    if (n < 100000000) return 8;\n    // Will not reach 10 digits in DigitGen()\n    //if (n < 1000000000) return 9;\n    //return 10;\n    return 9;\n}\n\ninline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {\n    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };\n    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);\n    const DiyFp wp_w = Mp - W;\n    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);\n    uint64_t p2 = Mp.f & (one.f - 1);\n    int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]\n    *len = 0;\n\n    while (kappa > 0) {\n        uint32_t d = 0;\n        switch (kappa) {\n            case  9: d = p1 /  100000000; p1 %=  100000000; break;\n            case  8: d = p1 /   10000000; p1 %=   10000000; break;\n            case  7: d = p1 /    1000000; p1 %=    1000000; break;\n            case  6: d = p1 /     100000; p1 %=     100000; break;\n            case  5: d = p1 /      10000; p1 %=      10000; break;\n            case  4: d = p1 /       1000; p1 %=       1000; break;\n            case  3: d = p1 /        100; p1 %=        100; break;\n            case  2: d = p1 /         10; p1 %=         10; break;\n            case  1: d = p1;              p1 =           0; break;\n            default:;\n        }\n        if (d || *len)\n            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));\n        kappa--;\n        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;\n        if (tmp <= delta) {\n            *K += kappa;\n            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);\n            return;\n        }\n    }\n\n    // kappa = 0\n    for (;;) {\n        p2 *= 10;\n        delta *= 10;\n        char d = static_cast<char>(p2 >> -one.e);\n        if (d || *len)\n            buffer[(*len)++] = static_cast<char>('0' + d);\n        p2 &= one.f - 1;\n        kappa--;\n        if (p2 < delta) {\n            *K += kappa;\n            int index = -kappa;\n            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));\n            return;\n        }\n    }\n}\n\ninline void Grisu2(double value, char* buffer, int* length, int* K) {\n    const DiyFp v(value);\n    DiyFp w_m, w_p;\n    v.NormalizedBoundaries(&w_m, &w_p);\n\n    const DiyFp c_mk = GetCachedPower(w_p.e, K);\n    const DiyFp W = v.Normalize() * c_mk;\n    DiyFp Wp = w_p * c_mk;\n    DiyFp Wm = w_m * c_mk;\n    Wm.f++;\n    Wp.f--;\n    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);\n}\n\ninline char* WriteExponent(int K, char* buffer) {\n    if (K < 0) {\n        *buffer++ = '-';\n        K = -K;\n    }\n\n    if (K >= 100) {\n        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));\n        K %= 100;\n        const char* d = GetDigitsLut() + K * 2;\n        *buffer++ = d[0];\n        *buffer++ = d[1];\n    }\n    else if (K >= 10) {\n        const char* d = GetDigitsLut() + K * 2;\n        *buffer++ = d[0];\n        *buffer++ = d[1];\n    }\n    else\n        *buffer++ = static_cast<char>('0' + static_cast<char>(K));\n\n    return buffer;\n}\n\ninline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {\n    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk\n\n    if (0 <= k && kk <= 21) {\n        // 1234e7 -> 12340000000\n        for (int i = length; i < kk; i++)\n            buffer[i] = '0';\n        buffer[kk] = '.';\n        buffer[kk + 1] = '0';\n        return &buffer[kk + 2];\n    }\n    else if (0 < kk && kk <= 21) {\n        // 1234e-2 -> 12.34\n        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));\n        buffer[kk] = '.';\n        if (0 > k + maxDecimalPlaces) {\n            // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1\n            // Remove extra trailing zeros (at least one) after truncation.\n            for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)\n                if (buffer[i] != '0')\n                    return &buffer[i + 1];\n            return &buffer[kk + 2]; // Reserve one zero\n        }\n        else\n            return &buffer[length + 1];\n    }\n    else if (-6 < kk && kk <= 0) {\n        // 1234e-6 -> 0.001234\n        const int offset = 2 - kk;\n        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));\n        buffer[0] = '0';\n        buffer[1] = '.';\n        for (int i = 2; i < offset; i++)\n            buffer[i] = '0';\n        if (length - kk > maxDecimalPlaces) {\n            // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1\n            // Remove extra trailing zeros (at least one) after truncation.\n            for (int i = maxDecimalPlaces + 1; i > 2; i--)\n                if (buffer[i] != '0')\n                    return &buffer[i + 1];\n            return &buffer[3]; // Reserve one zero\n        }\n        else\n            return &buffer[length + offset];\n    }\n    else if (kk < -maxDecimalPlaces) {\n        // Truncate to zero\n        buffer[0] = '0';\n        buffer[1] = '.';\n        buffer[2] = '0';\n        return &buffer[3];\n    }\n    else if (length == 1) {\n        // 1e30\n        buffer[1] = 'e';\n        return WriteExponent(kk - 1, &buffer[2]);\n    }\n    else {\n        // 1234e30 -> 1.234e33\n        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));\n        buffer[1] = '.';\n        buffer[length + 1] = 'e';\n        return WriteExponent(kk - 1, &buffer[0 + length + 2]);\n    }\n}\n\ninline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {\n    RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);\n    Double d(value);\n    if (d.IsZero()) {\n        if (d.Sign())\n            *buffer++ = '-';     // -0.0, Issue #289\n        buffer[0] = '0';\n        buffer[1] = '.';\n        buffer[2] = '0';\n        return &buffer[3];\n    }\n    else {\n        if (value < 0) {\n            *buffer++ = '-';\n            value = -value;\n        }\n        int length, K;\n        Grisu2(value, buffer, &length, &K);\n        return Prettify(buffer, length, K, maxDecimalPlaces);\n    }\n}\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_DTOA_\n"
  },
  {
    "path": "src/json/rapidjson/internal/ieee754.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_IEEE754_\n#define RAPIDJSON_IEEE754_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\nclass Double {\npublic:\n    Double() {}\n    Double(double d) : d_(d) {}\n    Double(uint64_t u) : u_(u) {}\n\n    double Value() const { return d_; }\n    uint64_t Uint64Value() const { return u_; }\n\n    double NextPositiveDouble() const {\n        RAPIDJSON_ASSERT(!Sign());\n        return Double(u_ + 1).Value();\n    }\n\n    bool Sign() const { return (u_ & kSignMask) != 0; }\n    uint64_t Significand() const { return u_ & kSignificandMask; }\n    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }\n\n    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }\n    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }\n    bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }\n    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }\n    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }\n\n    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }\n    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }\n    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }\n\n    static int EffectiveSignificandSize(int order) {\n        if (order >= -1021)\n            return 53;\n        else if (order <= -1074)\n            return 0;\n        else\n            return order + 1074;\n    }\n\nprivate:\n    static const int kSignificandSize = 52;\n    static const int kExponentBias = 0x3FF;\n    static const int kDenormalExponent = 1 - kExponentBias;\n    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);\n    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);\n    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);\n    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);\n\n    union {\n        double d_;\n        uint64_t u_;\n    };\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_IEEE754_\n"
  },
  {
    "path": "src/json/rapidjson/internal/itoa.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ITOA_\n#define RAPIDJSON_ITOA_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\ninline const char* GetDigitsLut() {\n    static const char cDigitsLut[200] = {\n        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',\n        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',\n        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',\n        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',\n        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',\n        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',\n        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',\n        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',\n        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',\n        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'\n    };\n    return cDigitsLut;\n}\n\ninline char* u32toa(uint32_t value, char* buffer) {\n    RAPIDJSON_ASSERT(buffer != 0);\n\n    const char* cDigitsLut = GetDigitsLut();\n\n    if (value < 10000) {\n        const uint32_t d1 = (value / 100) << 1;\n        const uint32_t d2 = (value % 100) << 1;\n\n        if (value >= 1000)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= 100)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= 10)\n            *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n    }\n    else if (value < 100000000) {\n        // value = bbbbcccc\n        const uint32_t b = value / 10000;\n        const uint32_t c = value % 10000;\n\n        const uint32_t d1 = (b / 100) << 1;\n        const uint32_t d2 = (b % 100) << 1;\n\n        const uint32_t d3 = (c / 100) << 1;\n        const uint32_t d4 = (c % 100) << 1;\n\n        if (value >= 10000000)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= 1000000)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= 100000)\n            *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n    }\n    else {\n        // value = aabbbbcccc in decimal\n\n        const uint32_t a = value / 100000000; // 1 to 42\n        value %= 100000000;\n\n        if (a >= 10) {\n            const unsigned i = a << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a));\n\n        const uint32_t b = value / 10000; // 0 to 9999\n        const uint32_t c = value % 10000; // 0 to 9999\n\n        const uint32_t d1 = (b / 100) << 1;\n        const uint32_t d2 = (b % 100) << 1;\n\n        const uint32_t d3 = (c / 100) << 1;\n        const uint32_t d4 = (c % 100) << 1;\n\n        *buffer++ = cDigitsLut[d1];\n        *buffer++ = cDigitsLut[d1 + 1];\n        *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n    }\n    return buffer;\n}\n\ninline char* i32toa(int32_t value, char* buffer) {\n    RAPIDJSON_ASSERT(buffer != 0);\n    uint32_t u = static_cast<uint32_t>(value);\n    if (value < 0) {\n        *buffer++ = '-';\n        u = ~u + 1;\n    }\n\n    return u32toa(u, buffer);\n}\n\ninline char* u64toa(uint64_t value, char* buffer) {\n    RAPIDJSON_ASSERT(buffer != 0);\n    const char* cDigitsLut = GetDigitsLut();\n    const uint64_t  kTen8 = 100000000;\n    const uint64_t  kTen9 = kTen8 * 10;\n    const uint64_t kTen10 = kTen8 * 100;\n    const uint64_t kTen11 = kTen8 * 1000;\n    const uint64_t kTen12 = kTen8 * 10000;\n    const uint64_t kTen13 = kTen8 * 100000;\n    const uint64_t kTen14 = kTen8 * 1000000;\n    const uint64_t kTen15 = kTen8 * 10000000;\n    const uint64_t kTen16 = kTen8 * kTen8;\n\n    if (value < kTen8) {\n        uint32_t v = static_cast<uint32_t>(value);\n        if (v < 10000) {\n            const uint32_t d1 = (v / 100) << 1;\n            const uint32_t d2 = (v % 100) << 1;\n\n            if (v >= 1000)\n                *buffer++ = cDigitsLut[d1];\n            if (v >= 100)\n                *buffer++ = cDigitsLut[d1 + 1];\n            if (v >= 10)\n                *buffer++ = cDigitsLut[d2];\n            *buffer++ = cDigitsLut[d2 + 1];\n        }\n        else {\n            // value = bbbbcccc\n            const uint32_t b = v / 10000;\n            const uint32_t c = v % 10000;\n\n            const uint32_t d1 = (b / 100) << 1;\n            const uint32_t d2 = (b % 100) << 1;\n\n            const uint32_t d3 = (c / 100) << 1;\n            const uint32_t d4 = (c % 100) << 1;\n\n            if (value >= 10000000)\n                *buffer++ = cDigitsLut[d1];\n            if (value >= 1000000)\n                *buffer++ = cDigitsLut[d1 + 1];\n            if (value >= 100000)\n                *buffer++ = cDigitsLut[d2];\n            *buffer++ = cDigitsLut[d2 + 1];\n\n            *buffer++ = cDigitsLut[d3];\n            *buffer++ = cDigitsLut[d3 + 1];\n            *buffer++ = cDigitsLut[d4];\n            *buffer++ = cDigitsLut[d4 + 1];\n        }\n    }\n    else if (value < kTen16) {\n        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);\n        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);\n\n        const uint32_t b0 = v0 / 10000;\n        const uint32_t c0 = v0 % 10000;\n\n        const uint32_t d1 = (b0 / 100) << 1;\n        const uint32_t d2 = (b0 % 100) << 1;\n\n        const uint32_t d3 = (c0 / 100) << 1;\n        const uint32_t d4 = (c0 % 100) << 1;\n\n        const uint32_t b1 = v1 / 10000;\n        const uint32_t c1 = v1 % 10000;\n\n        const uint32_t d5 = (b1 / 100) << 1;\n        const uint32_t d6 = (b1 % 100) << 1;\n\n        const uint32_t d7 = (c1 / 100) << 1;\n        const uint32_t d8 = (c1 % 100) << 1;\n\n        if (value >= kTen15)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= kTen14)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= kTen13)\n            *buffer++ = cDigitsLut[d2];\n        if (value >= kTen12)\n            *buffer++ = cDigitsLut[d2 + 1];\n        if (value >= kTen11)\n            *buffer++ = cDigitsLut[d3];\n        if (value >= kTen10)\n            *buffer++ = cDigitsLut[d3 + 1];\n        if (value >= kTen9)\n            *buffer++ = cDigitsLut[d4];\n\n        *buffer++ = cDigitsLut[d4 + 1];\n        *buffer++ = cDigitsLut[d5];\n        *buffer++ = cDigitsLut[d5 + 1];\n        *buffer++ = cDigitsLut[d6];\n        *buffer++ = cDigitsLut[d6 + 1];\n        *buffer++ = cDigitsLut[d7];\n        *buffer++ = cDigitsLut[d7 + 1];\n        *buffer++ = cDigitsLut[d8];\n        *buffer++ = cDigitsLut[d8 + 1];\n    }\n    else {\n        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844\n        value %= kTen16;\n\n        if (a < 10)\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a));\n        else if (a < 100) {\n            const uint32_t i = a << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else if (a < 1000) {\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));\n\n            const uint32_t i = (a % 100) << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else {\n            const uint32_t i = (a / 100) << 1;\n            const uint32_t j = (a % 100) << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n            *buffer++ = cDigitsLut[j];\n            *buffer++ = cDigitsLut[j + 1];\n        }\n\n        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);\n        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);\n\n        const uint32_t b0 = v0 / 10000;\n        const uint32_t c0 = v0 % 10000;\n\n        const uint32_t d1 = (b0 / 100) << 1;\n        const uint32_t d2 = (b0 % 100) << 1;\n\n        const uint32_t d3 = (c0 / 100) << 1;\n        const uint32_t d4 = (c0 % 100) << 1;\n\n        const uint32_t b1 = v1 / 10000;\n        const uint32_t c1 = v1 % 10000;\n\n        const uint32_t d5 = (b1 / 100) << 1;\n        const uint32_t d6 = (b1 % 100) << 1;\n\n        const uint32_t d7 = (c1 / 100) << 1;\n        const uint32_t d8 = (c1 % 100) << 1;\n\n        *buffer++ = cDigitsLut[d1];\n        *buffer++ = cDigitsLut[d1 + 1];\n        *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n        *buffer++ = cDigitsLut[d5];\n        *buffer++ = cDigitsLut[d5 + 1];\n        *buffer++ = cDigitsLut[d6];\n        *buffer++ = cDigitsLut[d6 + 1];\n        *buffer++ = cDigitsLut[d7];\n        *buffer++ = cDigitsLut[d7 + 1];\n        *buffer++ = cDigitsLut[d8];\n        *buffer++ = cDigitsLut[d8 + 1];\n    }\n\n    return buffer;\n}\n\ninline char* i64toa(int64_t value, char* buffer) {\n    RAPIDJSON_ASSERT(buffer != 0);\n    uint64_t u = static_cast<uint64_t>(value);\n    if (value < 0) {\n        *buffer++ = '-';\n        u = ~u + 1;\n    }\n\n    return u64toa(u, buffer);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ITOA_\n"
  },
  {
    "path": "src/json/rapidjson/internal/meta.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_META_H_\n#define RAPIDJSON_INTERNAL_META_H_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#if defined(_MSC_VER) && !defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(6334)\n#endif\n\n#if RAPIDJSON_HAS_CXX11_TYPETRAITS\n#include <type_traits>\n#endif\n\n//@cond RAPIDJSON_INTERNAL\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching\ntemplate <typename T> struct Void { typedef void Type; };\n\n///////////////////////////////////////////////////////////////////////////////\n// BoolType, TrueType, FalseType\n//\ntemplate <bool Cond> struct BoolType {\n    static const bool Value = Cond;\n    typedef BoolType Type;\n};\ntypedef BoolType<true> TrueType;\ntypedef BoolType<false> FalseType;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr\n//\n\ntemplate <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };\ntemplate <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };\ntemplate <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};\ntemplate <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};\n\ntemplate <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};\ntemplate <> struct AndExprCond<true, true> : TrueType {};\ntemplate <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};\ntemplate <> struct OrExprCond<false, false> : FalseType {};\n\ntemplate <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};\ntemplate <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};\ntemplate <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};\ntemplate <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// AddConst, MaybeAddConst, RemoveConst\ntemplate <typename T> struct AddConst { typedef const T Type; };\ntemplate <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};\ntemplate <typename T> struct RemoveConst { typedef T Type; };\ntemplate <typename T> struct RemoveConst<const T> { typedef T Type; };\n\n\n///////////////////////////////////////////////////////////////////////////////\n// IsSame, IsConst, IsMoreConst, IsPointer\n//\ntemplate <typename T, typename U> struct IsSame : FalseType {};\ntemplate <typename T> struct IsSame<T, T> : TrueType {};\n\ntemplate <typename T> struct IsConst : FalseType {};\ntemplate <typename T> struct IsConst<const T> : TrueType {};\n\ntemplate <typename CT, typename T>\nstruct IsMoreConst\n    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,\n              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};\n\ntemplate <typename T> struct IsPointer : FalseType {};\ntemplate <typename T> struct IsPointer<T*> : TrueType {};\n\n///////////////////////////////////////////////////////////////////////////////\n// IsBaseOf\n//\n#if RAPIDJSON_HAS_CXX11_TYPETRAITS\n\ntemplate <typename B, typename D> struct IsBaseOf\n    : BoolType< ::std::is_base_of<B,D>::value> {};\n\n#else // simplified version adopted from Boost\n\ntemplate<typename B, typename D> struct IsBaseOfImpl {\n    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);\n    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);\n\n    typedef char (&Yes)[1];\n    typedef char (&No) [2];\n\n    template <typename T>\n    static Yes Check(const D*, T);\n    static No  Check(const B*, int);\n\n    struct Host {\n        operator const B*() const;\n        operator const D*();\n    };\n\n    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };\n};\n\ntemplate <typename B, typename D> struct IsBaseOf\n    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};\n\n#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS\n\n\n//////////////////////////////////////////////////////////////////////////\n// EnableIf / DisableIf\n//\ntemplate <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };\ntemplate <typename T> struct EnableIfCond<false, T> { /* empty */ };\n\ntemplate <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };\ntemplate <typename T> struct DisableIfCond<true, T> { /* empty */ };\n\ntemplate <typename Condition, typename T = void>\nstruct EnableIf : EnableIfCond<Condition::Value, T> {};\n\ntemplate <typename Condition, typename T = void>\nstruct DisableIf : DisableIfCond<Condition::Value, T> {};\n\n// SFINAE helpers\nstruct SfinaeTag {};\ntemplate <typename T> struct RemoveSfinaeTag;\ntemplate <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };\n\n#define RAPIDJSON_REMOVEFPTR_(type) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \\\n        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type\n\n#define RAPIDJSON_ENABLEIF(cond) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL\n\n#define RAPIDJSON_DISABLEIF(cond) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL\n\n#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond), \\\n         RAPIDJSON_REMOVEFPTR_(returntype)>::Type\n\n#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond), \\\n         RAPIDJSON_REMOVEFPTR_(returntype)>::Type\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n//@endcond\n\n#if defined(_MSC_VER) && !defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_META_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/pow10.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_POW10_\n#define RAPIDJSON_POW10_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Computes integer powers of 10 in double (10.0^n).\n/*! This function uses lookup table for fast and accurate results.\n    \\param n non-negative exponent. Must <= 308.\n    \\return 10.0^n\n*/\ninline double Pow10(int n) {\n    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes\n        1e+0,  \n        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, \n        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,\n        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,\n        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,\n        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,\n        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,\n        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,\n        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,\n        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,\n        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,\n        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,\n        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,\n        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,\n        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,\n        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,\n        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308\n    };\n    RAPIDJSON_ASSERT(n >= 0 && n <= 308);\n    return e[n];\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_POW10_\n"
  },
  {
    "path": "src/json/rapidjson/internal/regex.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_REGEX_H_\n#define RAPIDJSON_INTERNAL_REGEX_H_\n\n#include \"src/json/rapidjson/allocators.h\"\n#include \"src/json/rapidjson/stream.h\"\n#include \"stack.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(switch-enum)\nRAPIDJSON_DIAG_OFF(implicit-fallthrough)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#if __GNUC__ >= 7\nRAPIDJSON_DIAG_OFF(implicit-fallthrough)\n#endif\n#endif\n\n#ifndef RAPIDJSON_REGEX_VERBOSE\n#define RAPIDJSON_REGEX_VERBOSE 0\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n///////////////////////////////////////////////////////////////////////////////\n// DecodedStream\n\ntemplate <typename SourceStream, typename Encoding>\nclass DecodedStream {\npublic:\n    DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }\n    unsigned Peek() { return codepoint_; }\n    unsigned Take() {\n        unsigned c = codepoint_;\n        if (c) // No further decoding when '\\0'\n            Decode();\n        return c;\n    }\n\nprivate:\n    void Decode() {\n        if (!Encoding::Decode(ss_, &codepoint_))\n            codepoint_ = 0;\n    }\n\n    SourceStream& ss_;\n    unsigned codepoint_;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericRegex\n\nstatic const SizeType kRegexInvalidState = ~SizeType(0);  //!< Represents an invalid index in GenericRegex::State::out, out1\nstatic const SizeType kRegexInvalidRange = ~SizeType(0);\n\ntemplate <typename Encoding, typename Allocator>\nclass GenericRegexSearch;\n\n//! Regular expression engine with subset of ECMAscript grammar.\n/*!\n    Supported regular expression syntax:\n    - \\c ab     Concatenation\n    - \\c a|b    Alternation\n    - \\c a?     Zero or one\n    - \\c a*     Zero or more\n    - \\c a+     One or more\n    - \\c a{3}   Exactly 3 times\n    - \\c a{3,}  At least 3 times\n    - \\c a{3,5} 3 to 5 times\n    - \\c (ab)   Grouping\n    - \\c ^a     At the beginning\n    - \\c a$     At the end\n    - \\c .      Any character\n    - \\c [abc]  Character classes\n    - \\c [a-c]  Character class range\n    - \\c [a-z0-9_] Character class combination\n    - \\c [^abc] Negated character classes\n    - \\c [^a-c] Negated character class range\n    - \\c [\\b]   Backspace (U+0008)\n    - \\c \\\\| \\\\\\\\ ...  Escape characters\n    - \\c \\\\f Form feed (U+000C)\n    - \\c \\\\n Line feed (U+000A)\n    - \\c \\\\r Carriage return (U+000D)\n    - \\c \\\\t Tab (U+0009)\n    - \\c \\\\v Vertical tab (U+000B)\n\n    \\note This is a Thompson NFA engine, implemented with reference to \n        Cox, Russ. \"Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).\", \n        https://swtch.com/~rsc/regexp/regexp1.html \n*/\ntemplate <typename Encoding, typename Allocator = CrtAllocator>\nclass GenericRegex {\npublic:\n    typedef Encoding EncodingType;\n    typedef typename Encoding::Ch Ch;\n    template <typename, typename> friend class GenericRegexSearch;\n\n    GenericRegex(const Ch* source, Allocator* allocator = 0) : \n        ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), \n        states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), \n        anchorBegin_(), anchorEnd_()\n    {\n        GenericStringStream<Encoding> ss(source);\n        DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);\n        Parse(ds);\n    }\n\n    ~GenericRegex()\n    {\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    bool IsValid() const {\n        return root_ != kRegexInvalidState;\n    }\n\nprivate:\n    enum Operator {\n        kZeroOrOne,\n        kZeroOrMore,\n        kOneOrMore,\n        kConcatenation,\n        kAlternation,\n        kLeftParenthesis\n    };\n\n    static const unsigned kAnyCharacterClass = 0xFFFFFFFF;   //!< For '.'\n    static const unsigned kRangeCharacterClass = 0xFFFFFFFE;\n    static const unsigned kRangeNegationFlag = 0x80000000;\n\n    struct Range {\n        unsigned start; // \n        unsigned end;\n        SizeType next;\n    };\n\n    struct State {\n        SizeType out;     //!< Equals to kInvalid for matching state\n        SizeType out1;    //!< Equals to non-kInvalid for split\n        SizeType rangeStart;\n        unsigned codepoint;\n    };\n\n    struct Frag {\n        Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}\n        SizeType start;\n        SizeType out; //!< link-list of all output states\n        SizeType minIndex;\n    };\n\n    State& GetState(SizeType index) {\n        RAPIDJSON_ASSERT(index < stateCount_);\n        return states_.template Bottom<State>()[index];\n    }\n\n    const State& GetState(SizeType index) const {\n        RAPIDJSON_ASSERT(index < stateCount_);\n        return states_.template Bottom<State>()[index];\n    }\n\n    Range& GetRange(SizeType index) {\n        RAPIDJSON_ASSERT(index < rangeCount_);\n        return ranges_.template Bottom<Range>()[index];\n    }\n\n    const Range& GetRange(SizeType index) const {\n        RAPIDJSON_ASSERT(index < rangeCount_);\n        return ranges_.template Bottom<Range>()[index];\n    }\n\n    template <typename InputStream>\n    void Parse(DecodedStream<InputStream, Encoding>& ds) {\n        Stack<Allocator> operandStack(allocator_, 256);    // Frag\n        Stack<Allocator> operatorStack(allocator_, 256);   // Operator\n        Stack<Allocator> atomCountStack(allocator_, 256);  // unsigned (Atom per parenthesis)\n\n        *atomCountStack.template Push<unsigned>() = 0;\n\n        unsigned codepoint;\n        while (ds.Peek() != 0) {\n            switch (codepoint = ds.Take()) {\n                case '^':\n                    anchorBegin_ = true;\n                    break;\n\n                case '$':\n                    anchorEnd_ = true;\n                    break;\n\n                case '|':\n                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)\n                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))\n                            return;\n                    *operatorStack.template Push<Operator>() = kAlternation;\n                    *atomCountStack.template Top<unsigned>() = 0;\n                    break;\n\n                case '(':\n                    *operatorStack.template Push<Operator>() = kLeftParenthesis;\n                    *atomCountStack.template Push<unsigned>() = 0;\n                    break;\n\n                case ')':\n                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)\n                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))\n                            return;\n                    if (operatorStack.Empty())\n                        return;\n                    operatorStack.template Pop<Operator>(1);\n                    atomCountStack.template Pop<unsigned>(1);\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n                    break;\n\n                case '?':\n                    if (!Eval(operandStack, kZeroOrOne))\n                        return;\n                    break;\n\n                case '*':\n                    if (!Eval(operandStack, kZeroOrMore))\n                        return;\n                    break;\n\n                case '+':\n                    if (!Eval(operandStack, kOneOrMore))\n                        return;\n                    break;\n\n                case '{':\n                    {\n                        unsigned n, m;\n                        if (!ParseUnsigned(ds, &n))\n                            return;\n\n                        if (ds.Peek() == ',') {\n                            ds.Take();\n                            if (ds.Peek() == '}')\n                                m = kInfinityQuantifier;\n                            else if (!ParseUnsigned(ds, &m) || m < n)\n                                return;\n                        }\n                        else\n                            m = n;\n\n                        if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')\n                            return;\n                        ds.Take();\n                    }\n                    break;\n\n                case '.':\n                    PushOperand(operandStack, kAnyCharacterClass);\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n                    break;\n\n                case '[':\n                    {\n                        SizeType range;\n                        if (!ParseRange(ds, &range))\n                            return;\n                        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);\n                        GetState(s).rangeStart = range;\n                        *operandStack.template Push<Frag>() = Frag(s, s, s);\n                    }\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n                    break;\n\n                case '\\\\': // Escape character\n                    if (!CharacterEscape(ds, &codepoint))\n                        return; // Unsupported escape character\n                    // fall through to default\n\n                default: // Pattern character\n                    PushOperand(operandStack, codepoint);\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n            }\n        }\n\n        while (!operatorStack.Empty())\n            if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))\n                return;\n\n        // Link the operand to matching state.\n        if (operandStack.GetSize() == sizeof(Frag)) {\n            Frag* e = operandStack.template Pop<Frag>(1);\n            Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));\n            root_ = e->start;\n\n#if RAPIDJSON_REGEX_VERBOSE\n            printf(\"root: %d\\n\", root_);\n            for (SizeType i = 0; i < stateCount_ ; i++) {\n                State& s = GetState(i);\n                printf(\"[%2d] out: %2d out1: %2d c: '%c'\\n\", i, s.out, s.out1, (char)s.codepoint);\n            }\n            printf(\"\\n\");\n#endif\n        }\n    }\n\n    SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {\n        State* s = states_.template Push<State>();\n        s->out = out;\n        s->out1 = out1;\n        s->codepoint = codepoint;\n        s->rangeStart = kRegexInvalidRange;\n        return stateCount_++;\n    }\n\n    void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {\n        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);\n        *operandStack.template Push<Frag>() = Frag(s, s, s);\n    }\n\n    void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {\n        if (*atomCountStack.template Top<unsigned>())\n            *operatorStack.template Push<Operator>() = kConcatenation;\n        (*atomCountStack.template Top<unsigned>())++;\n    }\n\n    SizeType Append(SizeType l1, SizeType l2) {\n        SizeType old = l1;\n        while (GetState(l1).out != kRegexInvalidState)\n            l1 = GetState(l1).out;\n        GetState(l1).out = l2;\n        return old;\n    }\n\n    void Patch(SizeType l, SizeType s) {\n        for (SizeType next; l != kRegexInvalidState; l = next) {\n            next = GetState(l).out;\n            GetState(l).out = s;\n        }\n    }\n\n    bool Eval(Stack<Allocator>& operandStack, Operator op) {\n        switch (op) {\n            case kConcatenation:\n                RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);\n                {\n                    Frag e2 = *operandStack.template Pop<Frag>(1);\n                    Frag e1 = *operandStack.template Pop<Frag>(1);\n                    Patch(e1.out, e2.start);\n                    *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));\n                }\n                return true;\n\n            case kAlternation:\n                if (operandStack.GetSize() >= sizeof(Frag) * 2) {\n                    Frag e2 = *operandStack.template Pop<Frag>(1);\n                    Frag e1 = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(e1.start, e2.start, 0);\n                    *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));\n                    return true;\n                }\n                return false;\n\n            case kZeroOrOne:\n                if (operandStack.GetSize() >= sizeof(Frag)) {\n                    Frag e = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(kRegexInvalidState, e.start, 0);\n                    *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);\n                    return true;\n                }\n                return false;\n\n            case kZeroOrMore:\n                if (operandStack.GetSize() >= sizeof(Frag)) {\n                    Frag e = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(kRegexInvalidState, e.start, 0);\n                    Patch(e.out, s);\n                    *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);\n                    return true;\n                }\n                return false;\n\n            case kOneOrMore:\n                if (operandStack.GetSize() >= sizeof(Frag)) {\n                    Frag e = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(kRegexInvalidState, e.start, 0);\n                    Patch(e.out, s);\n                    *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);\n                    return true;\n                }\n                return false;\n\n            default: \n                // syntax error (e.g. unclosed kLeftParenthesis)\n                return false;\n        }\n    }\n\n    bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {\n        RAPIDJSON_ASSERT(n <= m);\n        RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));\n\n        if (n == 0) {\n            if (m == 0)                             // a{0} not support\n                return false;\n            else if (m == kInfinityQuantifier)\n                Eval(operandStack, kZeroOrMore);    // a{0,} -> a*\n            else {\n                Eval(operandStack, kZeroOrOne);         // a{0,5} -> a?\n                for (unsigned i = 0; i < m - 1; i++)\n                    CloneTopOperand(operandStack);      // a{0,5} -> a? a? a? a? a?\n                for (unsigned i = 0; i < m - 1; i++)\n                    Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?\n            }\n            return true;\n        }\n\n        for (unsigned i = 0; i < n - 1; i++)        // a{3} -> a a a\n            CloneTopOperand(operandStack);\n\n        if (m == kInfinityQuantifier)\n            Eval(operandStack, kOneOrMore);         // a{3,} -> a a a+\n        else if (m > n) {\n            CloneTopOperand(operandStack);          // a{3,5} -> a a a a\n            Eval(operandStack, kZeroOrOne);         // a{3,5} -> a a a a?\n            for (unsigned i = n; i < m - 1; i++)\n                CloneTopOperand(operandStack);      // a{3,5} -> a a a a? a?\n            for (unsigned i = n; i < m; i++)\n                Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?\n        }\n\n        for (unsigned i = 0; i < n - 1; i++)\n            Eval(operandStack, kConcatenation);     // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?\n\n        return true;\n    }\n\n    static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }\n\n    void CloneTopOperand(Stack<Allocator>& operandStack) {\n        const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation\n        SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)\n        State* s = states_.template Push<State>(count);\n        memcpy(s, &GetState(src.minIndex), count * sizeof(State));\n        for (SizeType j = 0; j < count; j++) {\n            if (s[j].out != kRegexInvalidState)\n                s[j].out += count;\n            if (s[j].out1 != kRegexInvalidState)\n                s[j].out1 += count;\n        }\n        *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);\n        stateCount_ += count;\n    }\n\n    template <typename InputStream>\n    bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {\n        unsigned r = 0;\n        if (ds.Peek() < '0' || ds.Peek() > '9')\n            return false;\n        while (ds.Peek() >= '0' && ds.Peek() <= '9') {\n            if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295\n                return false; // overflow\n            r = r * 10 + (ds.Take() - '0');\n        }\n        *u = r;\n        return true;\n    }\n\n    template <typename InputStream>\n    bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {\n        bool isBegin = true;\n        bool negate = false;\n        int step = 0;\n        SizeType start = kRegexInvalidRange;\n        SizeType current = kRegexInvalidRange;\n        unsigned codepoint;\n        while ((codepoint = ds.Take()) != 0) {\n            if (isBegin) {\n                isBegin = false;\n                if (codepoint == '^') {\n                    negate = true;\n                    continue;\n                }\n            }\n\n            switch (codepoint) {\n            case ']':\n                if (start == kRegexInvalidRange)\n                    return false;   // Error: nothing inside []\n                if (step == 2) { // Add trailing '-'\n                    SizeType r = NewRange('-');\n                    RAPIDJSON_ASSERT(current != kRegexInvalidRange);\n                    GetRange(current).next = r;\n                }\n                if (negate)\n                    GetRange(start).start |= kRangeNegationFlag;\n                *range = start;\n                return true;\n\n            case '\\\\':\n                if (ds.Peek() == 'b') {\n                    ds.Take();\n                    codepoint = 0x0008; // Escape backspace character\n                }\n                else if (!CharacterEscape(ds, &codepoint))\n                    return false;\n                // fall through to default\n\n            default:\n                switch (step) {\n                case 1:\n                    if (codepoint == '-') {\n                        step++;\n                        break;\n                    }\n                    // fall through to step 0 for other characters\n\n                case 0:\n                    {\n                        SizeType r = NewRange(codepoint);\n                        if (current != kRegexInvalidRange)\n                            GetRange(current).next = r;\n                        if (start == kRegexInvalidRange)\n                            start = r;\n                        current = r;\n                    }\n                    step = 1;\n                    break;\n\n                default:\n                    RAPIDJSON_ASSERT(step == 2);\n                    GetRange(current).end = codepoint;\n                    step = 0;\n                }\n            }\n        }\n        return false;\n    }\n    \n    SizeType NewRange(unsigned codepoint) {\n        Range* r = ranges_.template Push<Range>();\n        r->start = r->end = codepoint;\n        r->next = kRegexInvalidRange;\n        return rangeCount_++;\n    }\n\n    template <typename InputStream>\n    bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {\n        unsigned codepoint;\n        switch (codepoint = ds.Take()) {\n            case '^':\n            case '$':\n            case '|':\n            case '(':\n            case ')':\n            case '?':\n            case '*':\n            case '+':\n            case '.':\n            case '[':\n            case ']':\n            case '{':\n            case '}':\n            case '\\\\':\n                *escapedCodepoint = codepoint; return true;\n            case 'f': *escapedCodepoint = 0x000C; return true;\n            case 'n': *escapedCodepoint = 0x000A; return true;\n            case 'r': *escapedCodepoint = 0x000D; return true;\n            case 't': *escapedCodepoint = 0x0009; return true;\n            case 'v': *escapedCodepoint = 0x000B; return true;\n            default:\n                return false; // Unsupported escape character\n        }\n    }\n\n    Allocator* ownAllocator_;\n    Allocator* allocator_;\n    Stack<Allocator> states_;\n    Stack<Allocator> ranges_;\n    SizeType root_;\n    SizeType stateCount_;\n    SizeType rangeCount_;\n\n    static const unsigned kInfinityQuantifier = ~0u;\n\n    // For SearchWithAnchoring()\n    bool anchorBegin_;\n    bool anchorEnd_;\n};\n\ntemplate <typename RegexType, typename Allocator = CrtAllocator>\nclass GenericRegexSearch {\npublic:\n    typedef typename RegexType::EncodingType Encoding;\n    typedef typename Encoding::Ch Ch;\n\n    GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : \n        regex_(regex), allocator_(allocator), ownAllocator_(0),\n        state0_(allocator, 0), state1_(allocator, 0), stateSet_()\n    {\n        RAPIDJSON_ASSERT(regex_.IsValid());\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n        stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));\n        state0_.template Reserve<SizeType>(regex_.stateCount_);\n        state1_.template Reserve<SizeType>(regex_.stateCount_);\n    }\n\n    ~GenericRegexSearch() {\n        Allocator::Free(stateSet_);\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    template <typename InputStream>\n    bool Match(InputStream& is) {\n        return SearchWithAnchoring(is, true, true);\n    }\n\n    bool Match(const Ch* s) {\n        GenericStringStream<Encoding> is(s);\n        return Match(is);\n    }\n\n    template <typename InputStream>\n    bool Search(InputStream& is) {\n        return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);\n    }\n\n    bool Search(const Ch* s) {\n        GenericStringStream<Encoding> is(s);\n        return Search(is);\n    }\n\nprivate:\n    typedef typename RegexType::State State;\n    typedef typename RegexType::Range Range;\n\n    template <typename InputStream>\n    bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {\n        DecodedStream<InputStream, Encoding> ds(is);\n\n        state0_.Clear();\n        Stack<Allocator> *current = &state0_, *next = &state1_;\n        const size_t stateSetSize = GetStateSetSize();\n        std::memset(stateSet_, 0, stateSetSize);\n\n        bool matched = AddState(*current, regex_.root_);\n        unsigned codepoint;\n        while (!current->Empty() && (codepoint = ds.Take()) != 0) {\n            std::memset(stateSet_, 0, stateSetSize);\n            next->Clear();\n            matched = false;\n            for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {\n                const State& sr = regex_.GetState(*s);\n                if (sr.codepoint == codepoint ||\n                    sr.codepoint == RegexType::kAnyCharacterClass || \n                    (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))\n                {\n                    matched = AddState(*next, sr.out) || matched;\n                    if (!anchorEnd && matched)\n                        return true;\n                }\n                if (!anchorBegin)\n                    AddState(*next, regex_.root_);\n            }\n            internal::Swap(current, next);\n        }\n\n        return matched;\n    }\n\n    size_t GetStateSetSize() const {\n        return (regex_.stateCount_ + 31) / 32 * 4;\n    }\n\n    // Return whether the added states is a match state\n    bool AddState(Stack<Allocator>& l, SizeType index) {\n        RAPIDJSON_ASSERT(index != kRegexInvalidState);\n\n        const State& s = regex_.GetState(index);\n        if (s.out1 != kRegexInvalidState) { // Split\n            bool matched = AddState(l, s.out);\n            return AddState(l, s.out1) || matched;\n        }\n        else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {\n            stateSet_[index >> 5] |= (1u << (index & 31));\n            *l.template PushUnsafe<SizeType>() = index;\n        }\n        return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.\n    }\n\n    bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {\n        bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;\n        while (rangeIndex != kRegexInvalidRange) {\n            const Range& r = regex_.GetRange(rangeIndex);\n            if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)\n                return yes;\n            rangeIndex = r.next;\n        }\n        return !yes;\n    }\n\n    const RegexType& regex_;\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    Stack<Allocator> state0_;\n    Stack<Allocator> state1_;\n    uint32_t* stateSet_;\n};\n\ntypedef GenericRegex<UTF8<> > Regex;\ntypedef GenericRegexSearch<Regex> RegexSearch;\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#if defined(__clang__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_REGEX_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/stack.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_STACK_H_\n#define RAPIDJSON_INTERNAL_STACK_H_\n\n#include \"src/json/rapidjson/allocators.h\"\n#include \"swap.h\"\n#include <cstddef>\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n///////////////////////////////////////////////////////////////////////////////\n// Stack\n\n//! A type-unsafe stack for storing different types of data.\n/*! \\tparam Allocator Allocator for allocating stack memory.\n*/\ntemplate <typename Allocator>\nclass Stack {\npublic:\n    // Optimization note: Do not allocate memory for stack_ in constructor.\n    // Do it lazily when first Push() -> Expand() -> Resize().\n    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Stack(Stack&& rhs)\n        : allocator_(rhs.allocator_),\n          ownAllocator_(rhs.ownAllocator_),\n          stack_(rhs.stack_),\n          stackTop_(rhs.stackTop_),\n          stackEnd_(rhs.stackEnd_),\n          initialCapacity_(rhs.initialCapacity_)\n    {\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.stack_ = 0;\n        rhs.stackTop_ = 0;\n        rhs.stackEnd_ = 0;\n        rhs.initialCapacity_ = 0;\n    }\n#endif\n\n    ~Stack() {\n        Destroy();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Stack& operator=(Stack&& rhs) {\n        if (&rhs != this)\n        {\n            Destroy();\n\n            allocator_ = rhs.allocator_;\n            ownAllocator_ = rhs.ownAllocator_;\n            stack_ = rhs.stack_;\n            stackTop_ = rhs.stackTop_;\n            stackEnd_ = rhs.stackEnd_;\n            initialCapacity_ = rhs.initialCapacity_;\n\n            rhs.allocator_ = 0;\n            rhs.ownAllocator_ = 0;\n            rhs.stack_ = 0;\n            rhs.stackTop_ = 0;\n            rhs.stackEnd_ = 0;\n            rhs.initialCapacity_ = 0;\n        }\n        return *this;\n    }\n#endif\n\n    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {\n        internal::Swap(allocator_, rhs.allocator_);\n        internal::Swap(ownAllocator_, rhs.ownAllocator_);\n        internal::Swap(stack_, rhs.stack_);\n        internal::Swap(stackTop_, rhs.stackTop_);\n        internal::Swap(stackEnd_, rhs.stackEnd_);\n        internal::Swap(initialCapacity_, rhs.initialCapacity_);\n    }\n\n    void Clear() { stackTop_ = stack_; }\n\n    void ShrinkToFit() { \n        if (Empty()) {\n            // If the stack is empty, completely deallocate the memory.\n            Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)\n            stack_ = 0;\n            stackTop_ = 0;\n            stackEnd_ = 0;\n        }\n        else\n            Resize(GetSize());\n    }\n\n    // Optimization note: try to minimize the size of this function for force inline.\n    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.\n    template<typename T>\n    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {\n         // Expand the stack if needed\n        if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))\n            Expand<T>(count);\n    }\n\n    template<typename T>\n    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {\n        Reserve<T>(count);\n        return PushUnsafe<T>(count);\n    }\n\n    template<typename T>\n    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {\n        RAPIDJSON_ASSERT(stackTop_);\n        RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));\n        T* ret = reinterpret_cast<T*>(stackTop_);\n        stackTop_ += sizeof(T) * count;\n        return ret;\n    }\n\n    template<typename T>\n    T* Pop(size_t count) {\n        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));\n        stackTop_ -= count * sizeof(T);\n        return reinterpret_cast<T*>(stackTop_);\n    }\n\n    template<typename T>\n    T* Top() { \n        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));\n        return reinterpret_cast<T*>(stackTop_ - sizeof(T));\n    }\n\n    template<typename T>\n    const T* Top() const {\n        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));\n        return reinterpret_cast<T*>(stackTop_ - sizeof(T));\n    }\n\n    template<typename T>\n    T* End() { return reinterpret_cast<T*>(stackTop_); }\n\n    template<typename T>\n    const T* End() const { return reinterpret_cast<T*>(stackTop_); }\n\n    template<typename T>\n    T* Bottom() { return reinterpret_cast<T*>(stack_); }\n\n    template<typename T>\n    const T* Bottom() const { return reinterpret_cast<T*>(stack_); }\n\n    bool HasAllocator() const {\n        return allocator_ != 0;\n    }\n\n    Allocator& GetAllocator() {\n        RAPIDJSON_ASSERT(allocator_);\n        return *allocator_;\n    }\n\n    bool Empty() const { return stackTop_ == stack_; }\n    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }\n    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }\n\nprivate:\n    template<typename T>\n    void Expand(size_t count) {\n        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.\n        size_t newCapacity;\n        if (stack_ == 0) {\n            if (!allocator_)\n                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n            newCapacity = initialCapacity_;\n        } else {\n            newCapacity = GetCapacity();\n            newCapacity += (newCapacity + 1) / 2;\n        }\n        size_t newSize = GetSize() + sizeof(T) * count;\n        if (newCapacity < newSize)\n            newCapacity = newSize;\n\n        Resize(newCapacity);\n    }\n\n    void Resize(size_t newCapacity) {\n        const size_t size = GetSize();  // Backup the current size\n        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));\n        stackTop_ = stack_ + size;\n        stackEnd_ = stack_ + newCapacity;\n    }\n\n    void Destroy() {\n        Allocator::Free(stack_);\n        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack\n    }\n\n    // Prohibit copy constructor & assignment operator.\n    Stack(const Stack&);\n    Stack& operator=(const Stack&);\n\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    char *stack_;\n    char *stackTop_;\n    char *stackEnd_;\n    size_t initialCapacity_;\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_STACK_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/strfunc.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_\n#define RAPIDJSON_INTERNAL_STRFUNC_H_\n\n#include \"src/json/rapidjson/stream.h\"\n#include <cwchar>\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Custom strlen() which works on different character types.\n/*! \\tparam Ch Character type (e.g. char, wchar_t, short)\n    \\param s Null-terminated input string.\n    \\return Number of characters in the string. \n    \\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.\n*/\ntemplate <typename Ch>\ninline SizeType StrLen(const Ch* s) {\n    RAPIDJSON_ASSERT(s != 0);\n    const Ch* p = s;\n    while (*p) ++p;\n    return SizeType(p - s);\n}\n\ntemplate <>\ninline SizeType StrLen(const char* s) {\n    return SizeType(std::strlen(s));\n}\n\ntemplate <>\ninline SizeType StrLen(const wchar_t* s) {\n    return SizeType(std::wcslen(s));\n}\n\n//! Returns number of code points in a encoded string.\ntemplate<typename Encoding>\nbool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {\n    RAPIDJSON_ASSERT(s != 0);\n    RAPIDJSON_ASSERT(outCount != 0);\n    GenericStringStream<Encoding> is(s);\n    const typename Encoding::Ch* end = s + length;\n    SizeType count = 0;\n    while (is.src_ < end) {\n        unsigned codepoint;\n        if (!Encoding::Decode(is, &codepoint))\n            return false;\n        count++;\n    }\n    *outCount = count;\n    return true;\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_INTERNAL_STRFUNC_H_\n"
  },
  {
    "path": "src/json/rapidjson/internal/strtod.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_STRTOD_\n#define RAPIDJSON_STRTOD_\n\n#include \"ieee754.h\"\n#include \"biginteger.h\"\n#include \"diyfp.h\"\n#include \"pow10.h\"\n#include <climits>\n#include <limits>\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\ninline double FastPath(double significand, int exp) {\n    if (exp < -308)\n        return 0.0;\n    else if (exp >= 0)\n        return significand * internal::Pow10(exp);\n    else\n        return significand / internal::Pow10(-exp);\n}\n\ninline double StrtodNormalPrecision(double d, int p) {\n    if (p < -308) {\n        // Prevent expSum < -308, making Pow10(p) = 0\n        d = FastPath(d, -308);\n        d = FastPath(d, p + 308);\n    }\n    else\n        d = FastPath(d, p);\n    return d;\n}\n\ntemplate <typename T>\ninline T Min3(T a, T b, T c) {\n    T m = a;\n    if (m > b) m = b;\n    if (m > c) m = c;\n    return m;\n}\n\ninline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {\n    const Double db(b);\n    const uint64_t bInt = db.IntegerSignificand();\n    const int bExp = db.IntegerExponent();\n    const int hExp = bExp - 1;\n\n    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;\n\n    // Adjust for decimal exponent\n    if (dExp >= 0) {\n        dS_Exp2 += dExp;\n        dS_Exp5 += dExp;\n    }\n    else {\n        bS_Exp2 -= dExp;\n        bS_Exp5 -= dExp;\n        hS_Exp2 -= dExp;\n        hS_Exp5 -= dExp;\n    }\n\n    // Adjust for binary exponent\n    if (bExp >= 0)\n        bS_Exp2 += bExp;\n    else {\n        dS_Exp2 -= bExp;\n        hS_Exp2 -= bExp;\n    }\n\n    // Adjust for half ulp exponent\n    if (hExp >= 0)\n        hS_Exp2 += hExp;\n    else {\n        dS_Exp2 -= hExp;\n        bS_Exp2 -= hExp;\n    }\n\n    // Remove common power of two factor from all three scaled values\n    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);\n    dS_Exp2 -= common_Exp2;\n    bS_Exp2 -= common_Exp2;\n    hS_Exp2 -= common_Exp2;\n\n    BigInteger dS = d;\n    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);\n\n    BigInteger bS(bInt);\n    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);\n\n    BigInteger hS(1);\n    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);\n\n    BigInteger delta(0);\n    dS.Difference(bS, &delta);\n\n    return delta.Compare(hS);\n}\n\ninline bool StrtodFast(double d, int p, double* result) {\n    // Use fast path for string-to-double conversion if possible\n    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/\n    if (p > 22  && p < 22 + 16) {\n        // Fast Path Cases In Disguise\n        d *= internal::Pow10(p - 22);\n        p = 22;\n    }\n\n    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1\n        *result = FastPath(d, p);\n        return true;\n    }\n    else\n        return false;\n}\n\n// Compute an approximation and see if it is within 1/2 ULP\ninline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {\n    uint64_t significand = 0;\n    int i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    \n    for (; i < dLen; i++) {\n        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||\n            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))\n            break;\n        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');\n    }\n    \n    if (i < dLen && decimals[i] >= '5') // Rounding\n        significand++;\n\n    int remaining = dLen - i;\n    const int kUlpShift = 3;\n    const int kUlp = 1 << kUlpShift;\n    int64_t error = (remaining == 0) ? 0 : kUlp / 2;\n\n    DiyFp v(significand, 0);\n    v = v.Normalize();\n    error <<= -v.e;\n\n    dExp += remaining;\n\n    int actualExp;\n    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);\n    if (actualExp != dExp) {\n        static const DiyFp kPow10[] = {\n            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60),  // 10^1\n            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57),  // 10^2\n            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54),  // 10^3\n            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50),  // 10^4\n            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47),  // 10^5\n            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44),  // 10^6\n            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40)   // 10^7\n        };\n        int adjustment = dExp - actualExp;\n        RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);\n        v = v * kPow10[adjustment - 1];\n        if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit\n            error += kUlp / 2;\n    }\n\n    v = v * cachedPower;\n\n    error += kUlp + (error == 0 ? 0 : 1);\n\n    const int oldExp = v.e;\n    v = v.Normalize();\n    error <<= oldExp - v.e;\n\n    const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);\n    int precisionSize = 64 - effectiveSignificandSize;\n    if (precisionSize + kUlpShift >= 64) {\n        int scaleExp = (precisionSize + kUlpShift) - 63;\n        v.f >>= scaleExp;\n        v.e += scaleExp; \n        error = (error >> scaleExp) + 1 + kUlp;\n        precisionSize -= scaleExp;\n    }\n\n    DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);\n    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;\n    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;\n    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {\n        rounded.f++;\n        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)\n            rounded.f >>= 1;\n            rounded.e++;\n        }\n    }\n\n    *result = rounded.ToDouble();\n\n    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);\n}\n\ninline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {\n    RAPIDJSON_ASSERT(dLen >= 0);\n    const BigInteger dInt(decimals, static_cast<unsigned>(dLen));\n    Double a(approx);\n    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);\n    if (cmp < 0)\n        return a.Value();  // within half ULP\n    else if (cmp == 0) {\n        // Round towards even\n        if (a.Significand() & 1)\n            return a.NextPositiveDouble();\n        else\n            return a.Value();\n    }\n    else // adjustment\n        return a.NextPositiveDouble();\n}\n\ninline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {\n    RAPIDJSON_ASSERT(d >= 0.0);\n    RAPIDJSON_ASSERT(length >= 1);\n\n    double result = 0.0;\n    if (StrtodFast(d, p, &result))\n        return result;\n\n    RAPIDJSON_ASSERT(length <= INT_MAX);\n    int dLen = static_cast<int>(length);\n\n    RAPIDJSON_ASSERT(length >= decimalPosition);\n    RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);\n    int dExpAdjust = static_cast<int>(length - decimalPosition);\n\n    RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);\n    int dExp = exp - dExpAdjust;\n\n    // Make sure length+dExp does not overflow\n    RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);\n\n    // Trim leading zeros\n    while (dLen > 0 && *decimals == '0') {\n        dLen--;\n        decimals++;\n    }\n\n    // Trim trailing zeros\n    while (dLen > 0 && decimals[dLen - 1] == '0') {\n        dLen--;\n        dExp++;\n    }\n\n    if (dLen == 0) { // Buffer only contains zeros.\n        return 0.0;\n    }\n\n    // Trim right-most digits\n    const int kMaxDecimalDigit = 767 + 1;\n    if (dLen > kMaxDecimalDigit) {\n        dExp += dLen - kMaxDecimalDigit;\n        dLen = kMaxDecimalDigit;\n    }\n\n    // If too small, underflow to zero.\n    // Any x <= 10^-324 is interpreted as zero.\n    if (dLen + dExp <= -324)\n        return 0.0;\n\n    // If too large, overflow to infinity.\n    // Any x >= 10^309 is interpreted as +infinity.\n    if (dLen + dExp > 309)\n        return std::numeric_limits<double>::infinity();\n\n    if (StrtodDiyFp(decimals, dLen, dExp, &result))\n        return result;\n\n    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison\n    return StrtodBigInteger(result, decimals, dLen, dExp);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STRTOD_\n"
  },
  {
    "path": "src/json/rapidjson/internal/swap.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_SWAP_H_\n#define RAPIDJSON_INTERNAL_SWAP_H_\n\n#include \"src/json/rapidjson/rapidjson.h\"\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Custom swap() to avoid dependency on C++ <algorithm> header\n/*! \\tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.\n    \\note This has the same semantics as std::swap().\n*/\ntemplate <typename T>\ninline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {\n    T tmp = a;\n        a = b;\n        b = tmp;\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_SWAP_H_\n"
  },
  {
    "path": "src/json/rapidjson/istreamwrapper.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ISTREAMWRAPPER_H_\n#define RAPIDJSON_ISTREAMWRAPPER_H_\n\n#include \"stream.h\"\n#include <iosfwd>\n#include <ios>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of \\c std::basic_istream into RapidJSON's Stream concept.\n/*!\n    The classes can be wrapped including but not limited to:\n\n    - \\c std::istringstream\n    - \\c std::stringstream\n    - \\c std::wistringstream\n    - \\c std::wstringstream\n    - \\c std::ifstream\n    - \\c std::fstream\n    - \\c std::wifstream\n    - \\c std::wfstream\n\n    \\tparam StreamType Class derived from \\c std::basic_istream.\n*/\n   \ntemplate <typename StreamType>\nclass BasicIStreamWrapper {\npublic:\n    typedef typename StreamType::char_type Ch;\n\n    //! Constructor.\n    /*!\n        \\param stream stream opened for read.\n    */\n    BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { \n        Read();\n    }\n\n    //! Constructor.\n    /*!\n        \\param stream stream opened for read.\n        \\param buffer user-supplied buffer.\n        \\param bufferSize size of buffer in bytes. Must >=4 bytes.\n    */\n    BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { \n        RAPIDJSON_ASSERT(bufferSize >= 4);\n        Read();\n    }\n\n    Ch Peek() const { return *current_; }\n    Ch Take() { Ch c = *current_; Read(); return c; }\n    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;\n    }\n\nprivate:\n    BasicIStreamWrapper();\n    BasicIStreamWrapper(const BasicIStreamWrapper&);\n    BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);\n\n    void Read() {\n        if (current_ < bufferLast_)\n            ++current_;\n        else if (!eof_) {\n            count_ += readCount_;\n            readCount_ = bufferSize_;\n            bufferLast_ = buffer_ + readCount_ - 1;\n            current_ = buffer_;\n\n            if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {\n                readCount_ = static_cast<size_t>(stream_.gcount());\n                *(bufferLast_ = buffer_ + readCount_) = '\\0';\n                eof_ = true;\n            }\n        }\n    }\n\n    StreamType &stream_;\n    Ch peekBuffer_[4], *buffer_;\n    size_t bufferSize_;\n    Ch *bufferLast_;\n    Ch *current_;\n    size_t readCount_;\n    size_t count_;  //!< Number of characters read\n    bool eof_;\n};\n\ntypedef BasicIStreamWrapper<std::istream> IStreamWrapper;\ntypedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;\n\n#if defined(__clang__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ISTREAMWRAPPER_H_\n"
  },
  {
    "path": "src/json/rapidjson/memorybuffer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_MEMORYBUFFER_H_\n#define RAPIDJSON_MEMORYBUFFER_H_\n\n#include \"stream.h\"\n#include \"src/json/rapidjson/internal/stack.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory output byte stream.\n/*!\n    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.\n\n    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.\n\n    Differences between MemoryBuffer and StringBuffer:\n    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. \n    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.\n\n    \\tparam Allocator type for allocating memory buffer.\n    \\note implements Stream concept\n*/\ntemplate <typename Allocator = CrtAllocator>\nstruct GenericMemoryBuffer {\n    typedef char Ch; // byte\n\n    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n    void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n    void Flush() {}\n\n    void Clear() { stack_.Clear(); }\n    void ShrinkToFit() { stack_.ShrinkToFit(); }\n    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }\n    void Pop(size_t count) { stack_.template Pop<Ch>(count); }\n\n    const Ch* GetBuffer() const {\n        return stack_.template Bottom<Ch>();\n    }\n\n    size_t GetSize() const { return stack_.GetSize(); }\n\n    static const size_t kDefaultCapacity = 256;\n    mutable internal::Stack<Allocator> stack_;\n};\n\ntypedef GenericMemoryBuffer<> MemoryBuffer;\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {\n    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_MEMORYBUFFER_H_\n"
  },
  {
    "path": "src/json/rapidjson/memorystream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_MEMORYSTREAM_H_\n#define RAPIDJSON_MEMORYSTREAM_H_\n\n#include \"stream.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(unreachable-code)\nRAPIDJSON_DIAG_OFF(missing-noreturn)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory input byte stream.\n/*!\n    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.\n\n    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.\n\n    Differences between MemoryStream and StringStream:\n    1. StringStream has encoding but MemoryStream is a byte stream.\n    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.\n    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().\n    \\note implements Stream concept\n*/\nstruct MemoryStream {\n    typedef char Ch; // byte\n\n    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}\n\n    Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\\0' : *src_; }\n    Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\\0' : *src_++; }\n    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return Tell() + 4 <= size_ ? src_ : 0;\n    }\n\n    const Ch* src_;     //!< Current read position.\n    const Ch* begin_;   //!< Original head of the string.\n    const Ch* end_;     //!< End of stream.\n    size_t size_;       //!< Size of the stream.\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_MEMORYBUFFER_H_\n"
  },
  {
    "path": "src/json/rapidjson/msinttypes/inttypes.h",
    "content": "// ISO C9x  compliant inttypes.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2013 Alexander Chemeris\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,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. Neither the name of the product nor the names of its contributors may\n//      be used to endorse or promote products derived from this software\n//      without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n// The above software in this distribution may have been modified by \n// THL A29 Limited (\"Tencent Modifications\"). \n// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.\n\n#ifndef _MSC_VER // [\n#error \"Use this header only with Microsoft Visual C++ compilers!\"\n#endif // _MSC_VER ]\n\n#ifndef _MSC_INTTYPES_H_ // [\n#define _MSC_INTTYPES_H_\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n#include \"stdint.h\"\n\n// miloyip: VC supports inttypes.h since VC2013\n#if _MSC_VER >= 1800\n#include <inttypes.h>\n#else\n\n// 7.8 Format conversion of integer types\n\ntypedef struct {\n   intmax_t quot;\n   intmax_t rem;\n} imaxdiv_t;\n\n// 7.8.1 Macros for format specifiers\n\n#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198\n\n// The fprintf macros for signed integers are:\n#define PRId8       \"d\"\n#define PRIi8       \"i\"\n#define PRIdLEAST8  \"d\"\n#define PRIiLEAST8  \"i\"\n#define PRIdFAST8   \"d\"\n#define PRIiFAST8   \"i\"\n\n#define PRId16       \"hd\"\n#define PRIi16       \"hi\"\n#define PRIdLEAST16  \"hd\"\n#define PRIiLEAST16  \"hi\"\n#define PRIdFAST16   \"hd\"\n#define PRIiFAST16   \"hi\"\n\n#define PRId32       \"I32d\"\n#define PRIi32       \"I32i\"\n#define PRIdLEAST32  \"I32d\"\n#define PRIiLEAST32  \"I32i\"\n#define PRIdFAST32   \"I32d\"\n#define PRIiFAST32   \"I32i\"\n\n#define PRId64       \"I64d\"\n#define PRIi64       \"I64i\"\n#define PRIdLEAST64  \"I64d\"\n#define PRIiLEAST64  \"I64i\"\n#define PRIdFAST64   \"I64d\"\n#define PRIiFAST64   \"I64i\"\n\n#define PRIdMAX     \"I64d\"\n#define PRIiMAX     \"I64i\"\n\n#define PRIdPTR     \"Id\"\n#define PRIiPTR     \"Ii\"\n\n// The fprintf macros for unsigned integers are:\n#define PRIo8       \"o\"\n#define PRIu8       \"u\"\n#define PRIx8       \"x\"\n#define PRIX8       \"X\"\n#define PRIoLEAST8  \"o\"\n#define PRIuLEAST8  \"u\"\n#define PRIxLEAST8  \"x\"\n#define PRIXLEAST8  \"X\"\n#define PRIoFAST8   \"o\"\n#define PRIuFAST8   \"u\"\n#define PRIxFAST8   \"x\"\n#define PRIXFAST8   \"X\"\n\n#define PRIo16       \"ho\"\n#define PRIu16       \"hu\"\n#define PRIx16       \"hx\"\n#define PRIX16       \"hX\"\n#define PRIoLEAST16  \"ho\"\n#define PRIuLEAST16  \"hu\"\n#define PRIxLEAST16  \"hx\"\n#define PRIXLEAST16  \"hX\"\n#define PRIoFAST16   \"ho\"\n#define PRIuFAST16   \"hu\"\n#define PRIxFAST16   \"hx\"\n#define PRIXFAST16   \"hX\"\n\n#define PRIo32       \"I32o\"\n#define PRIu32       \"I32u\"\n#define PRIx32       \"I32x\"\n#define PRIX32       \"I32X\"\n#define PRIoLEAST32  \"I32o\"\n#define PRIuLEAST32  \"I32u\"\n#define PRIxLEAST32  \"I32x\"\n#define PRIXLEAST32  \"I32X\"\n#define PRIoFAST32   \"I32o\"\n#define PRIuFAST32   \"I32u\"\n#define PRIxFAST32   \"I32x\"\n#define PRIXFAST32   \"I32X\"\n\n#define PRIo64       \"I64o\"\n#define PRIu64       \"I64u\"\n#define PRIx64       \"I64x\"\n#define PRIX64       \"I64X\"\n#define PRIoLEAST64  \"I64o\"\n#define PRIuLEAST64  \"I64u\"\n#define PRIxLEAST64  \"I64x\"\n#define PRIXLEAST64  \"I64X\"\n#define PRIoFAST64   \"I64o\"\n#define PRIuFAST64   \"I64u\"\n#define PRIxFAST64   \"I64x\"\n#define PRIXFAST64   \"I64X\"\n\n#define PRIoMAX     \"I64o\"\n#define PRIuMAX     \"I64u\"\n#define PRIxMAX     \"I64x\"\n#define PRIXMAX     \"I64X\"\n\n#define PRIoPTR     \"Io\"\n#define PRIuPTR     \"Iu\"\n#define PRIxPTR     \"Ix\"\n#define PRIXPTR     \"IX\"\n\n// The fscanf macros for signed integers are:\n#define SCNd8       \"d\"\n#define SCNi8       \"i\"\n#define SCNdLEAST8  \"d\"\n#define SCNiLEAST8  \"i\"\n#define SCNdFAST8   \"d\"\n#define SCNiFAST8   \"i\"\n\n#define SCNd16       \"hd\"\n#define SCNi16       \"hi\"\n#define SCNdLEAST16  \"hd\"\n#define SCNiLEAST16  \"hi\"\n#define SCNdFAST16   \"hd\"\n#define SCNiFAST16   \"hi\"\n\n#define SCNd32       \"ld\"\n#define SCNi32       \"li\"\n#define SCNdLEAST32  \"ld\"\n#define SCNiLEAST32  \"li\"\n#define SCNdFAST32   \"ld\"\n#define SCNiFAST32   \"li\"\n\n#define SCNd64       \"I64d\"\n#define SCNi64       \"I64i\"\n#define SCNdLEAST64  \"I64d\"\n#define SCNiLEAST64  \"I64i\"\n#define SCNdFAST64   \"I64d\"\n#define SCNiFAST64   \"I64i\"\n\n#define SCNdMAX     \"I64d\"\n#define SCNiMAX     \"I64i\"\n\n#ifdef _WIN64 // [\n#  define SCNdPTR     \"I64d\"\n#  define SCNiPTR     \"I64i\"\n#else  // _WIN64 ][\n#  define SCNdPTR     \"ld\"\n#  define SCNiPTR     \"li\"\n#endif  // _WIN64 ]\n\n// The fscanf macros for unsigned integers are:\n#define SCNo8       \"o\"\n#define SCNu8       \"u\"\n#define SCNx8       \"x\"\n#define SCNX8       \"X\"\n#define SCNoLEAST8  \"o\"\n#define SCNuLEAST8  \"u\"\n#define SCNxLEAST8  \"x\"\n#define SCNXLEAST8  \"X\"\n#define SCNoFAST8   \"o\"\n#define SCNuFAST8   \"u\"\n#define SCNxFAST8   \"x\"\n#define SCNXFAST8   \"X\"\n\n#define SCNo16       \"ho\"\n#define SCNu16       \"hu\"\n#define SCNx16       \"hx\"\n#define SCNX16       \"hX\"\n#define SCNoLEAST16  \"ho\"\n#define SCNuLEAST16  \"hu\"\n#define SCNxLEAST16  \"hx\"\n#define SCNXLEAST16  \"hX\"\n#define SCNoFAST16   \"ho\"\n#define SCNuFAST16   \"hu\"\n#define SCNxFAST16   \"hx\"\n#define SCNXFAST16   \"hX\"\n\n#define SCNo32       \"lo\"\n#define SCNu32       \"lu\"\n#define SCNx32       \"lx\"\n#define SCNX32       \"lX\"\n#define SCNoLEAST32  \"lo\"\n#define SCNuLEAST32  \"lu\"\n#define SCNxLEAST32  \"lx\"\n#define SCNXLEAST32  \"lX\"\n#define SCNoFAST32   \"lo\"\n#define SCNuFAST32   \"lu\"\n#define SCNxFAST32   \"lx\"\n#define SCNXFAST32   \"lX\"\n\n#define SCNo64       \"I64o\"\n#define SCNu64       \"I64u\"\n#define SCNx64       \"I64x\"\n#define SCNX64       \"I64X\"\n#define SCNoLEAST64  \"I64o\"\n#define SCNuLEAST64  \"I64u\"\n#define SCNxLEAST64  \"I64x\"\n#define SCNXLEAST64  \"I64X\"\n#define SCNoFAST64   \"I64o\"\n#define SCNuFAST64   \"I64u\"\n#define SCNxFAST64   \"I64x\"\n#define SCNXFAST64   \"I64X\"\n\n#define SCNoMAX     \"I64o\"\n#define SCNuMAX     \"I64u\"\n#define SCNxMAX     \"I64x\"\n#define SCNXMAX     \"I64X\"\n\n#ifdef _WIN64 // [\n#  define SCNoPTR     \"I64o\"\n#  define SCNuPTR     \"I64u\"\n#  define SCNxPTR     \"I64x\"\n#  define SCNXPTR     \"I64X\"\n#else  // _WIN64 ][\n#  define SCNoPTR     \"lo\"\n#  define SCNuPTR     \"lu\"\n#  define SCNxPTR     \"lx\"\n#  define SCNXPTR     \"lX\"\n#endif  // _WIN64 ]\n\n#endif // __STDC_FORMAT_MACROS ]\n\n// 7.8.2 Functions for greatest-width integer types\n\n// 7.8.2.1 The imaxabs function\n#define imaxabs _abs64\n\n// 7.8.2.2 The imaxdiv function\n\n// This is modified version of div() function from Microsoft's div.c found\n// in %MSVC.NET%\\crt\\src\\div.c\n#ifdef STATIC_IMAXDIV // [\nstatic\n#else // STATIC_IMAXDIV ][\n_inline\n#endif // STATIC_IMAXDIV ]\nimaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)\n{\n   imaxdiv_t result;\n\n   result.quot = numer / denom;\n   result.rem = numer % denom;\n\n   if (numer < 0 && result.rem > 0) {\n      // did division wrong; must fix up\n      ++result.quot;\n      result.rem -= denom;\n   }\n\n   return result;\n}\n\n// 7.8.2.3 The strtoimax and strtoumax functions\n#define strtoimax _strtoi64\n#define strtoumax _strtoui64\n\n// 7.8.2.4 The wcstoimax and wcstoumax functions\n#define wcstoimax _wcstoi64\n#define wcstoumax _wcstoui64\n\n#endif // _MSC_VER >= 1800\n\n#endif // _MSC_INTTYPES_H_ ]\n"
  },
  {
    "path": "src/json/rapidjson/msinttypes/stdint.h",
    "content": "// ISO C9x  compliant stdint.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2013 Alexander Chemeris\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,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. Neither the name of the product nor the names of its contributors may\n//      be used to endorse or promote products derived from this software\n//      without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n// The above software in this distribution may have been modified by \n// THL A29 Limited (\"Tencent Modifications\"). \n// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.\n\n#ifndef _MSC_VER // [\n#error \"Use this header only with Microsoft Visual C++ compilers!\"\n#endif // _MSC_VER ]\n\n#ifndef _MSC_STDINT_H_ // [\n#define _MSC_STDINT_H_\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.\n#if _MSC_VER >= 1600 // [\n#include <stdint.h>\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260\n\n#undef INT8_C\n#undef INT16_C\n#undef INT32_C\n#undef INT64_C\n#undef UINT8_C\n#undef UINT16_C\n#undef UINT32_C\n#undef UINT64_C\n\n// 7.18.4.1 Macros for minimum-width integer constants\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n// 7.18.4.2 Macros for greatest-width integer constants\n// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.\n// Check out Issue 9 for the details.\n#ifndef INTMAX_C //   [\n#  define INTMAX_C   INT64_C\n#endif // INTMAX_C    ]\n#ifndef UINTMAX_C //  [\n#  define UINTMAX_C  UINT64_C\n#endif // UINTMAX_C   ]\n\n#endif // __STDC_CONSTANT_MACROS ]\n\n#else // ] _MSC_VER >= 1700 [\n\n#include <limits.h>\n\n// For Visual Studio 6 in C++ mode and for many Visual Studio versions when\n// compiling for ARM we have to wrap <wchar.h> include with 'extern \"C++\" {}'\n// or compiler would give many errors like this:\n//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed\n#if defined(__cplusplus) && !defined(_M_ARM)\nextern \"C\" {\n#endif\n#  include <wchar.h>\n#if defined(__cplusplus) && !defined(_M_ARM)\n}\n#endif\n\n// Define _W64 macros to mark types changing their size, like intptr_t.\n#ifndef _W64\n#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300\n#     define _W64 __w64\n#  else\n#     define _W64\n#  endif\n#endif\n\n\n// 7.18.1 Integer types\n\n// 7.18.1.1 Exact-width integer types\n\n// Visual Studio 6 and Embedded Visual C++ 4 doesn't\n// realize that, e.g. char has the same size as __int8\n// so we give up on __intX for them.\n#if (_MSC_VER < 1300)\n   typedef signed char       int8_t;\n   typedef signed short      int16_t;\n   typedef signed int        int32_t;\n   typedef unsigned char     uint8_t;\n   typedef unsigned short    uint16_t;\n   typedef unsigned int      uint32_t;\n#else\n   typedef signed __int8     int8_t;\n   typedef signed __int16    int16_t;\n   typedef signed __int32    int32_t;\n   typedef unsigned __int8   uint8_t;\n   typedef unsigned __int16  uint16_t;\n   typedef unsigned __int32  uint32_t;\n#endif\ntypedef signed __int64       int64_t;\ntypedef unsigned __int64     uint64_t;\n\n\n// 7.18.1.2 Minimum-width integer types\ntypedef int8_t    int_least8_t;\ntypedef int16_t   int_least16_t;\ntypedef int32_t   int_least32_t;\ntypedef int64_t   int_least64_t;\ntypedef uint8_t   uint_least8_t;\ntypedef uint16_t  uint_least16_t;\ntypedef uint32_t  uint_least32_t;\ntypedef uint64_t  uint_least64_t;\n\n// 7.18.1.3 Fastest minimum-width integer types\ntypedef int8_t    int_fast8_t;\ntypedef int16_t   int_fast16_t;\ntypedef int32_t   int_fast32_t;\ntypedef int64_t   int_fast64_t;\ntypedef uint8_t   uint_fast8_t;\ntypedef uint16_t  uint_fast16_t;\ntypedef uint32_t  uint_fast32_t;\ntypedef uint64_t  uint_fast64_t;\n\n// 7.18.1.4 Integer types capable of holding object pointers\n#ifdef _WIN64 // [\n   typedef signed __int64    intptr_t;\n   typedef unsigned __int64  uintptr_t;\n#else // _WIN64 ][\n   typedef _W64 signed int   intptr_t;\n   typedef _W64 unsigned int uintptr_t;\n#endif // _WIN64 ]\n\n// 7.18.1.5 Greatest-width integer types\ntypedef int64_t   intmax_t;\ntypedef uint64_t  uintmax_t;\n\n\n// 7.18.2 Limits of specified-width integer types\n\n#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259\n\n// 7.18.2.1 Limits of exact-width integer types\n#define INT8_MIN     ((int8_t)_I8_MIN)\n#define INT8_MAX     _I8_MAX\n#define INT16_MIN    ((int16_t)_I16_MIN)\n#define INT16_MAX    _I16_MAX\n#define INT32_MIN    ((int32_t)_I32_MIN)\n#define INT32_MAX    _I32_MAX\n#define INT64_MIN    ((int64_t)_I64_MIN)\n#define INT64_MAX    _I64_MAX\n#define UINT8_MAX    _UI8_MAX\n#define UINT16_MAX   _UI16_MAX\n#define UINT32_MAX   _UI32_MAX\n#define UINT64_MAX   _UI64_MAX\n\n// 7.18.2.2 Limits of minimum-width integer types\n#define INT_LEAST8_MIN    INT8_MIN\n#define INT_LEAST8_MAX    INT8_MAX\n#define INT_LEAST16_MIN   INT16_MIN\n#define INT_LEAST16_MAX   INT16_MAX\n#define INT_LEAST32_MIN   INT32_MIN\n#define INT_LEAST32_MAX   INT32_MAX\n#define INT_LEAST64_MIN   INT64_MIN\n#define INT_LEAST64_MAX   INT64_MAX\n#define UINT_LEAST8_MAX   UINT8_MAX\n#define UINT_LEAST16_MAX  UINT16_MAX\n#define UINT_LEAST32_MAX  UINT32_MAX\n#define UINT_LEAST64_MAX  UINT64_MAX\n\n// 7.18.2.3 Limits of fastest minimum-width integer types\n#define INT_FAST8_MIN    INT8_MIN\n#define INT_FAST8_MAX    INT8_MAX\n#define INT_FAST16_MIN   INT16_MIN\n#define INT_FAST16_MAX   INT16_MAX\n#define INT_FAST32_MIN   INT32_MIN\n#define INT_FAST32_MAX   INT32_MAX\n#define INT_FAST64_MIN   INT64_MIN\n#define INT_FAST64_MAX   INT64_MAX\n#define UINT_FAST8_MAX   UINT8_MAX\n#define UINT_FAST16_MAX  UINT16_MAX\n#define UINT_FAST32_MAX  UINT32_MAX\n#define UINT_FAST64_MAX  UINT64_MAX\n\n// 7.18.2.4 Limits of integer types capable of holding object pointers\n#ifdef _WIN64 // [\n#  define INTPTR_MIN   INT64_MIN\n#  define INTPTR_MAX   INT64_MAX\n#  define UINTPTR_MAX  UINT64_MAX\n#else // _WIN64 ][\n#  define INTPTR_MIN   INT32_MIN\n#  define INTPTR_MAX   INT32_MAX\n#  define UINTPTR_MAX  UINT32_MAX\n#endif // _WIN64 ]\n\n// 7.18.2.5 Limits of greatest-width integer types\n#define INTMAX_MIN   INT64_MIN\n#define INTMAX_MAX   INT64_MAX\n#define UINTMAX_MAX  UINT64_MAX\n\n// 7.18.3 Limits of other integer types\n\n#ifdef _WIN64 // [\n#  define PTRDIFF_MIN  _I64_MIN\n#  define PTRDIFF_MAX  _I64_MAX\n#else  // _WIN64 ][\n#  define PTRDIFF_MIN  _I32_MIN\n#  define PTRDIFF_MAX  _I32_MAX\n#endif  // _WIN64 ]\n\n#define SIG_ATOMIC_MIN  INT_MIN\n#define SIG_ATOMIC_MAX  INT_MAX\n\n#ifndef SIZE_MAX // [\n#  ifdef _WIN64 // [\n#     define SIZE_MAX  _UI64_MAX\n#  else // _WIN64 ][\n#     define SIZE_MAX  _UI32_MAX\n#  endif // _WIN64 ]\n#endif // SIZE_MAX ]\n\n// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>\n#ifndef WCHAR_MIN // [\n#  define WCHAR_MIN  0\n#endif  // WCHAR_MIN ]\n#ifndef WCHAR_MAX // [\n#  define WCHAR_MAX  _UI16_MAX\n#endif  // WCHAR_MAX ]\n\n#define WINT_MIN  0\n#define WINT_MAX  _UI16_MAX\n\n#endif // __STDC_LIMIT_MACROS ]\n\n\n// 7.18.4 Limits of other integer types\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260\n\n// 7.18.4.1 Macros for minimum-width integer constants\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n// 7.18.4.2 Macros for greatest-width integer constants\n// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.\n// Check out Issue 9 for the details.\n#ifndef INTMAX_C //   [\n#  define INTMAX_C   INT64_C\n#endif // INTMAX_C    ]\n#ifndef UINTMAX_C //  [\n#  define UINTMAX_C  UINT64_C\n#endif // UINTMAX_C   ]\n\n#endif // __STDC_CONSTANT_MACROS ]\n\n#endif // _MSC_VER >= 1600 ]\n\n#endif // _MSC_STDINT_H_ ]\n"
  },
  {
    "path": "src/json/rapidjson/ostreamwrapper.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_OSTREAMWRAPPER_H_\n#define RAPIDJSON_OSTREAMWRAPPER_H_\n\n#include \"stream.h\"\n#include <iosfwd>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of \\c std::basic_ostream into RapidJSON's Stream concept.\n/*!\n    The classes can be wrapped including but not limited to:\n\n    - \\c std::ostringstream\n    - \\c std::stringstream\n    - \\c std::wpstringstream\n    - \\c std::wstringstream\n    - \\c std::ifstream\n    - \\c std::fstream\n    - \\c std::wofstream\n    - \\c std::wfstream\n\n    \\tparam StreamType Class derived from \\c std::basic_ostream.\n*/\n   \ntemplate <typename StreamType>\nclass BasicOStreamWrapper {\npublic:\n    typedef typename StreamType::char_type Ch;\n    BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}\n\n    void Put(Ch c) {\n        stream_.put(c);\n    }\n\n    void Flush() {\n        stream_.flush();\n    }\n\n    // Not implemented\n    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }\n    char Take() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    BasicOStreamWrapper(const BasicOStreamWrapper&);\n    BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);\n\n    StreamType& stream_;\n};\n\ntypedef BasicOStreamWrapper<std::ostream> OStreamWrapper;\ntypedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_OSTREAMWRAPPER_H_\n"
  },
  {
    "path": "src/json/rapidjson/pointer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_POINTER_H_\n#define RAPIDJSON_POINTER_H_\n\n#include \"document.h\"\n#include \"src/json/rapidjson/internal/itoa.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(switch-enum)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\nstatic const SizeType kPointerInvalidIndex = ~SizeType(0);  //!< Represents an invalid index in GenericPointer::Token\n\n//! Error code of parsing.\n/*! \\ingroup RAPIDJSON_ERRORS\n    \\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode\n*/\nenum PointerParseErrorCode {\n    kPointerParseErrorNone = 0,                     //!< The parse is successful\n\n    kPointerParseErrorTokenMustBeginWithSolidus,    //!< A token must begin with a '/'\n    kPointerParseErrorInvalidEscape,                //!< Invalid escape\n    kPointerParseErrorInvalidPercentEncoding,       //!< Invalid percent encoding in URI fragment\n    kPointerParseErrorCharacterMustPercentEncode    //!< A character must percent encoded in URI fragment\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericPointer\n\n//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.\n/*!\n    This class implements RFC 6901 \"JavaScript Object Notation (JSON) Pointer\" \n    (https://tools.ietf.org/html/rfc6901).\n\n    A JSON pointer is for identifying a specific value in a JSON document\n    (GenericDocument). It can simplify coding of DOM tree manipulation, because it\n    can access multiple-level depth of DOM tree with single API call.\n\n    After it parses a string representation (e.g. \"/foo/0\" or URI fragment \n    representation (e.g. \"#/foo/0\") into its internal representation (tokens),\n    it can be used to resolve a specific value in multiple documents, or sub-tree \n    of documents.\n\n    Contrary to GenericValue, Pointer can be copy constructed and copy assigned.\n    Apart from assignment, a Pointer cannot be modified after construction.\n\n    Although Pointer is very convenient, please aware that constructing Pointer\n    involves parsing and dynamic memory allocation. A special constructor with user-\n    supplied tokens eliminates these.\n\n    GenericPointer depends on GenericDocument and GenericValue.\n    \n    \\tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >\n    \\tparam Allocator The allocator type for allocating memory for internal representation.\n    \n    \\note GenericPointer uses same encoding of ValueType.\n    However, Allocator of GenericPointer is independent of Allocator of Value.\n*/\ntemplate <typename ValueType, typename Allocator = CrtAllocator>\nclass GenericPointer {\npublic:\n    typedef typename ValueType::EncodingType EncodingType;  //!< Encoding type from Value\n    typedef typename ValueType::Ch Ch;                      //!< Character type from Value\n\n    //! A token is the basic units of internal representation.\n    /*!\n        A JSON pointer string representation \"/foo/123\" is parsed to two tokens: \n        \"foo\" and 123. 123 will be represented in both numeric form and string form.\n        They are resolved according to the actual value type (object or array).\n\n        For token that are not numbers, or the numeric value is out of bound\n        (greater than limits of SizeType), they are only treated as string form\n        (i.e. the token's index will be equal to kPointerInvalidIndex).\n\n        This struct is public so that user can create a Pointer without parsing and \n        allocation, using a special constructor.\n    */\n    struct Token {\n        const Ch* name;             //!< Name of the token. It has null character at the end but it can contain null character.\n        SizeType length;            //!< Length of the name.\n        SizeType index;             //!< A valid array index, if it is not equal to kPointerInvalidIndex.\n    };\n\n    //!@name Constructors and destructor.\n    //@{\n\n    //! Default constructor.\n    GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}\n\n    //! Constructor that parses a string or URI fragment representation.\n    /*!\n        \\param source A null-terminated, string or URI fragment representation of JSON pointer.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n    */\n    explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source, internal::StrLen(source));\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Constructor that parses a string or URI fragment representation.\n    /*!\n        \\param source A string or URI fragment representation of JSON pointer.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n        \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n    */\n    explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source.c_str(), source.size());\n    }\n#endif\n\n    //! Constructor that parses a string or URI fragment representation, with length of the source string.\n    /*!\n        \\param source A string or URI fragment representation of JSON pointer.\n        \\param length Length of source.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n        \\note Slightly faster than the overload without length.\n    */\n    GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source, length);\n    }\n\n    //! Constructor with user-supplied tokens.\n    /*!\n        This constructor let user supplies const array of tokens.\n        This prevents the parsing process and eliminates allocation.\n        This is preferred for memory constrained environments.\n\n        \\param tokens An constant array of tokens representing the JSON pointer.\n        \\param tokenCount Number of tokens.\n\n        \\b Example\n        \\code\n        #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }\n        #define INDEX(i) { #i, sizeof(#i) - 1, i }\n\n        static const Pointer::Token kTokens[] = { NAME(\"foo\"), INDEX(123) };\n        static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));\n        // Equivalent to static const Pointer p(\"/foo/123\");\n\n        #undef NAME\n        #undef INDEX\n        \\endcode\n    */\n    GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}\n\n    //! Copy constructor.\n    GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        *this = rhs;\n    }\n\n    //! Copy constructor.\n    GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        *this = rhs;\n    }\n\n    //! Destructor.\n    ~GenericPointer() {\n        if (nameBuffer_)    // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.\n            Allocator::Free(tokens_);\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    //! Assignment operator.\n    GenericPointer& operator=(const GenericPointer& rhs) {\n        if (this != &rhs) {\n            // Do not delete ownAllcator\n            if (nameBuffer_)\n                Allocator::Free(tokens_);\n\n            tokenCount_ = rhs.tokenCount_;\n            parseErrorOffset_ = rhs.parseErrorOffset_;\n            parseErrorCode_ = rhs.parseErrorCode_;\n\n            if (rhs.nameBuffer_)\n                CopyFromRaw(rhs); // Normally parsed tokens.\n            else {\n                tokens_ = rhs.tokens_; // User supplied const tokens.\n                nameBuffer_ = 0;\n            }\n        }\n        return *this;\n    }\n\n    //! Swap the content of this pointer with an other.\n    /*!\n        \\param other The pointer to swap with.\n        \\note Constant complexity.\n    */\n    GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT {\n        internal::Swap(allocator_, other.allocator_);\n        internal::Swap(ownAllocator_, other.ownAllocator_);\n        internal::Swap(nameBuffer_, other.nameBuffer_);\n        internal::Swap(tokens_, other.tokens_);\n        internal::Swap(tokenCount_, other.tokenCount_);\n        internal::Swap(parseErrorOffset_, other.parseErrorOffset_);\n        internal::Swap(parseErrorCode_, other.parseErrorCode_);\n        return *this;\n    }\n\n    //! free-standing swap function helper\n    /*!\n        Helper function to enable support for common swap implementation pattern based on \\c std::swap:\n        \\code\n        void swap(MyClass& a, MyClass& b) {\n            using std::swap;\n            swap(a.pointer, b.pointer);\n            // ...\n        }\n        \\endcode\n        \\see Swap()\n     */\n    friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }\n\n    //@}\n\n    //!@name Append token\n    //@{\n\n    //! Append a token and return a new Pointer\n    /*!\n        \\param token Token to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const Token& token, Allocator* allocator = 0) const {\n        GenericPointer r;\n        r.allocator_ = allocator;\n        Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);\n        std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));\n        r.tokens_[tokenCount_].name = p;\n        r.tokens_[tokenCount_].length = token.length;\n        r.tokens_[tokenCount_].index = token.index;\n        return r;\n    }\n\n    //! Append a name token with length, and return a new Pointer\n    /*!\n        \\param name Name to be appended.\n        \\param length Length of name.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {\n        Token token = { name, length, kPointerInvalidIndex };\n        return Append(token, allocator);\n    }\n\n    //! Append a name token without length, and return a new Pointer\n    /*!\n        \\param name Name (const Ch*) to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))\n    Append(T* name, Allocator* allocator = 0) const {\n        return Append(name, internal::StrLen(name), allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Append a name token, and return a new Pointer\n    /*!\n        \\param name Name to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {\n        return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);\n    }\n#endif\n\n    //! Append a index token, and return a new Pointer\n    /*!\n        \\param index Index to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(SizeType index, Allocator* allocator = 0) const {\n        char buffer[21];\n        char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);\n        SizeType length = static_cast<SizeType>(end - buffer);\n        buffer[length] = '\\0';\n\n        if (sizeof(Ch) == 1) {\n            Token token = { reinterpret_cast<Ch*>(buffer), length, index };\n            return Append(token, allocator);\n        }\n        else {\n            Ch name[21];\n            for (size_t i = 0; i <= length; i++)\n                name[i] = static_cast<Ch>(buffer[i]);\n            Token token = { name, length, index };\n            return Append(token, allocator);\n        }\n    }\n\n    //! Append a token by value, and return a new Pointer\n    /*!\n        \\param token token to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {\n        if (token.IsString())\n            return Append(token.GetString(), token.GetStringLength(), allocator);\n        else {\n            RAPIDJSON_ASSERT(token.IsUint64());\n            RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));\n            return Append(static_cast<SizeType>(token.GetUint64()), allocator);\n        }\n    }\n\n    //!@name Handling Parse Error\n    //@{\n\n    //! Check whether this is a valid pointer.\n    bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }\n\n    //! Get the parsing error offset in code unit.\n    size_t GetParseErrorOffset() const { return parseErrorOffset_; }\n\n    //! Get the parsing error code.\n    PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }\n\n    //@}\n\n    //! Get the allocator of this pointer.\n    Allocator& GetAllocator() { return *allocator_; }\n\n    //!@name Tokens\n    //@{\n\n    //! Get the token array (const version only).\n    const Token* GetTokens() const { return tokens_; }\n\n    //! Get the number of tokens.\n    size_t GetTokenCount() const { return tokenCount_; }\n\n    //@}\n\n    //!@name Equality/inequality operators\n    //@{\n\n    //! Equality operator.\n    /*!\n        \\note When any pointers are invalid, always returns false.\n    */\n    bool operator==(const GenericPointer& rhs) const {\n        if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)\n            return false;\n\n        for (size_t i = 0; i < tokenCount_; i++) {\n            if (tokens_[i].index != rhs.tokens_[i].index ||\n                tokens_[i].length != rhs.tokens_[i].length || \n                (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    //! Inequality operator.\n    /*!\n        \\note When any pointers are invalid, always returns true.\n    */\n    bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }\n\n    //! Less than operator.\n    /*!\n        \\note Invalid pointers are always greater than valid ones.\n    */\n    bool operator<(const GenericPointer& rhs) const {\n        if (!IsValid())\n            return false;\n        if (!rhs.IsValid())\n            return true;\n\n        if (tokenCount_ != rhs.tokenCount_)\n            return tokenCount_ < rhs.tokenCount_;\n\n        for (size_t i = 0; i < tokenCount_; i++) {\n            if (tokens_[i].index != rhs.tokens_[i].index)\n                return tokens_[i].index < rhs.tokens_[i].index;\n\n            if (tokens_[i].length != rhs.tokens_[i].length)\n                return tokens_[i].length < rhs.tokens_[i].length;\n\n            if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))\n                return cmp < 0;\n        }\n\n        return false;\n    }\n\n    //@}\n\n    //!@name Stringify\n    //@{\n\n    //! Stringify the pointer into string representation.\n    /*!\n        \\tparam OutputStream Type of output stream.\n        \\param os The output stream.\n    */\n    template<typename OutputStream>\n    bool Stringify(OutputStream& os) const {\n        return Stringify<false, OutputStream>(os);\n    }\n\n    //! Stringify the pointer into URI fragment representation.\n    /*!\n        \\tparam OutputStream Type of output stream.\n        \\param os The output stream.\n    */\n    template<typename OutputStream>\n    bool StringifyUriFragment(OutputStream& os) const {\n        return Stringify<true, OutputStream>(os);\n    }\n\n    //@}\n\n    //!@name Create value\n    //@{\n\n    //! Create a value in a subtree.\n    /*!\n        If the value is not exist, it creates all parent values and a JSON Null value.\n        So it always succeed and return the newly created or existing value.\n\n        Remind that it may change types of parents according to tokens, so it \n        potentially removes previously stored values. For example, if a document \n        was an array, and \"/foo\" is used to create a value, then the document \n        will be changed to an object, and all existing array elements are lost.\n\n        \\param root Root value of a DOM subtree to be resolved. It can be any value other than document root.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\param alreadyExist If non-null, it stores whether the resolved value is already exist.\n        \\return The resolved newly created (a JSON Null value), or already exists value.\n    */\n    ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {\n        RAPIDJSON_ASSERT(IsValid());\n        ValueType* v = &root;\n        bool exist = true;\n        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            if (v->IsArray() && t->name[0] == '-' && t->length == 1) {\n                v->PushBack(ValueType().Move(), allocator);\n                v = &((*v)[v->Size() - 1]);\n                exist = false;\n            }\n            else {\n                if (t->index == kPointerInvalidIndex) { // must be object name\n                    if (!v->IsObject())\n                        v->SetObject(); // Change to Object\n                }\n                else { // object name or array index\n                    if (!v->IsArray() && !v->IsObject())\n                        v->SetArray(); // Change to Array\n                }\n\n                if (v->IsArray()) {\n                    if (t->index >= v->Size()) {\n                        v->Reserve(t->index + 1, allocator);\n                        while (t->index >= v->Size())\n                            v->PushBack(ValueType().Move(), allocator);\n                        exist = false;\n                    }\n                    v = &((*v)[t->index]);\n                }\n                else {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd()) {\n                        v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);\n                        v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end\n                        exist = false;\n                    }\n                    else\n                        v = &m->value;\n                }\n            }\n        }\n\n        if (alreadyExist)\n            *alreadyExist = exist;\n\n        return *v;\n    }\n\n    //! Creates a value in a document.\n    /*!\n        \\param document A document to be resolved.\n        \\param alreadyExist If non-null, it stores whether the resolved value is already exist.\n        \\return The resolved newly created, or already exists value.\n    */\n    template <typename stackAllocator>\n    ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {\n        return Create(document, document.GetAllocator(), alreadyExist);\n    }\n\n    //@}\n\n    //!@name Query value\n    //@{\n\n    //! Query a value in a subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.\n        \\return Pointer to the value if it can be resolved. Otherwise null.\n\n        \\note\n        There are only 3 situations when a value cannot be resolved:\n        1. A value in the path is not an array nor object.\n        2. An object value does not contain the token.\n        3. A token is out of range of an array value.\n\n        Use unresolvedTokenIndex to retrieve the token index.\n    */\n    ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {\n        RAPIDJSON_ASSERT(IsValid());\n        ValueType* v = &root;\n        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            switch (v->GetType()) {\n            case kObjectType:\n                {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd())\n                        break;\n                    v = &m->value;\n                }\n                continue;\n            case kArrayType:\n                if (t->index == kPointerInvalidIndex || t->index >= v->Size())\n                    break;\n                v = &((*v)[t->index]);\n                continue;\n            default:\n                break;\n            }\n\n            // Error: unresolved token\n            if (unresolvedTokenIndex)\n                *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);\n            return 0;\n        }\n        return v;\n    }\n\n    //! Query a const value in a const subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Pointer to the value if it can be resolved. Otherwise null.\n    */\n    const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { \n        return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);\n    }\n\n    //@}\n\n    //!@name Query a value with default\n    //@{\n\n    //! Query a value in a subtree with default value.\n    /*!\n        Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.\n        So that this function always succeed.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param defaultValue Default value to be cloned if the value was not exists.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        ValueType& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);\n    }\n\n    //! Query a value in a subtree with default null-terminated string.\n    ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        ValueType& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.SetString(defaultValue, allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Query a value in a subtree with default std::basic_string.\n    ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        ValueType& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.SetString(defaultValue, allocator);\n    }\n#endif\n\n    //! Query a value in a subtree with default primitive value.\n    /*!\n        \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {\n        return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);\n    }\n\n    //! Query a value in a document with default value.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n\n    //! Query a value in a document with default null-terminated string.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n    \n#if RAPIDJSON_HAS_STDSTRING\n    //! Query a value in a document with default std::basic_string.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n#endif\n\n    //! Query a value in a document with default primitive value.\n    /*!\n        \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T, typename stackAllocator>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n\n    //@}\n\n    //!@name Set a value\n    //@{\n\n    //! Set a value in a subtree, with move semantics.\n    /*!\n        It creates all parents if they are not exist or types are different to the tokens.\n        So this function always succeeds but potentially remove existing values.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param value Value to be set.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = value;\n    }\n\n    //! Set a value in a subtree, with copy semantics.\n    ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator).CopyFrom(value, allocator);\n    }\n\n    //! Set a null-terminated string in a subtree.\n    ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value, allocator).Move();\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Set a std::basic_string in a subtree.\n    ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value, allocator).Move();\n    }\n#endif\n\n    //! Set a primitive value in a subtree.\n    /*!\n        \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value).Move();\n    }\n\n    //! Set a value in a document, with move semantics.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {\n        return Create(document) = value;\n    }\n\n    //! Set a value in a document, with copy semantics.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {\n        return Create(document).CopyFrom(value, document.GetAllocator());\n    }\n\n    //! Set a null-terminated string in a document.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {\n        return Create(document) = ValueType(value, document.GetAllocator()).Move();\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Sets a std::basic_string in a document.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {\n        return Create(document) = ValueType(value, document.GetAllocator()).Move();\n    }\n#endif\n\n    //! Set a primitive value in a document.\n    /*!\n    \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T, typename stackAllocator>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n        Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {\n            return Create(document) = value;\n    }\n\n    //@}\n\n    //!@name Swap a value\n    //@{\n\n    //! Swap a value with a value in a subtree.\n    /*!\n        It creates all parents if they are not exist or types are different to the tokens.\n        So this function always succeeds but potentially remove existing values.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param value Value to be swapped.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator).Swap(value);\n    }\n\n    //! Swap a value with a value in a document.\n    template <typename stackAllocator>\n    ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {\n        return Create(document).Swap(value);\n    }\n\n    //@}\n\n    //! Erase a value in a subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Whether the resolved value is found and erased.\n\n        \\note Erasing with an empty pointer \\c Pointer(\"\"), i.e. the root, always fail and return false.\n    */\n    bool Erase(ValueType& root) const {\n        RAPIDJSON_ASSERT(IsValid());\n        if (tokenCount_ == 0) // Cannot erase the root\n            return false;\n\n        ValueType* v = &root;\n        const Token* last = tokens_ + (tokenCount_ - 1);\n        for (const Token *t = tokens_; t != last; ++t) {\n            switch (v->GetType()) {\n            case kObjectType:\n                {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd())\n                        return false;\n                    v = &m->value;\n                }\n                break;\n            case kArrayType:\n                if (t->index == kPointerInvalidIndex || t->index >= v->Size())\n                    return false;\n                v = &((*v)[t->index]);\n                break;\n            default:\n                return false;\n            }\n        }\n\n        switch (v->GetType()) {\n        case kObjectType:\n            return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));\n        case kArrayType:\n            if (last->index == kPointerInvalidIndex || last->index >= v->Size())\n                return false;\n            v->Erase(v->Begin() + last->index);\n            return true;\n        default:\n            return false;\n        }\n    }\n\nprivate:\n    //! Clone the content from rhs to this.\n    /*!\n        \\param rhs Source pointer.\n        \\param extraToken Extra tokens to be allocated.\n        \\param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.\n        \\return Start of non-occupied name buffer, for storing extra names.\n    */\n    Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {\n        if (!allocator_) // allocator is independently owned.\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n\n        size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens\n        for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)\n            nameBufferSize += t->length;\n\n        tokenCount_ = rhs.tokenCount_ + extraToken;\n        tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));\n        nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);\n        if (rhs.tokenCount_ > 0) {\n            std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));\n        }\n        if (nameBufferSize > 0) {\n            std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));\n        }\n\n        // Adjust pointers to name buffer\n        std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;\n        for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)\n            t->name += diff;\n\n        return nameBuffer_ + nameBufferSize;\n    }\n\n    //! Check whether a character should be percent-encoded.\n    /*!\n        According to RFC 3986 2.3 Unreserved Characters.\n        \\param c The character (code unit) to be tested.\n    */\n    bool NeedPercentEncode(Ch c) const {\n        return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');\n    }\n\n    //! Parse a JSON String or its URI fragment representation into tokens.\n#ifndef __clang__ // -Wdocumentation\n    /*!\n        \\param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.\n        \\param length Length of the source string.\n        \\note Source cannot be JSON String Representation of JSON Pointer, e.g. In \"/\\u0000\", \\u0000 will not be unescaped.\n    */\n#endif\n    void Parse(const Ch* source, size_t length) {\n        RAPIDJSON_ASSERT(source != NULL);\n        RAPIDJSON_ASSERT(nameBuffer_ == 0);\n        RAPIDJSON_ASSERT(tokens_ == 0);\n\n        // Create own allocator if user did not supply.\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n\n        // Count number of '/' as tokenCount\n        tokenCount_ = 0;\n        for (const Ch* s = source; s != source + length; s++) \n            if (*s == '/')\n                tokenCount_++;\n\n        Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));\n        Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);\n        size_t i = 0;\n\n        // Detect if it is a URI fragment\n        bool uriFragment = false;\n        if (source[i] == '#') {\n            uriFragment = true;\n            i++;\n        }\n\n        if (i != length && source[i] != '/') {\n            parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;\n            goto error;\n        }\n\n        while (i < length) {\n            RAPIDJSON_ASSERT(source[i] == '/');\n            i++; // consumes '/'\n\n            token->name = name;\n            bool isNumber = true;\n\n            while (i < length && source[i] != '/') {\n                Ch c = source[i];\n                if (uriFragment) {\n                    // Decoding percent-encoding for URI fragment\n                    if (c == '%') {\n                        PercentDecodeStream is(&source[i], source + length);\n                        GenericInsituStringStream<EncodingType> os(name);\n                        Ch* begin = os.PutBegin();\n                        if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {\n                            parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;\n                            goto error;\n                        }\n                        size_t len = os.PutEnd(begin);\n                        i += is.Tell() - 1;\n                        if (len == 1)\n                            c = *name;\n                        else {\n                            name += len;\n                            isNumber = false;\n                            i++;\n                            continue;\n                        }\n                    }\n                    else if (NeedPercentEncode(c)) {\n                        parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;\n                        goto error;\n                    }\n                }\n\n                i++;\n                \n                // Escaping \"~0\" -> '~', \"~1\" -> '/'\n                if (c == '~') {\n                    if (i < length) {\n                        c = source[i];\n                        if (c == '0')       c = '~';\n                        else if (c == '1')  c = '/';\n                        else {\n                            parseErrorCode_ = kPointerParseErrorInvalidEscape;\n                            goto error;\n                        }\n                        i++;\n                    }\n                    else {\n                        parseErrorCode_ = kPointerParseErrorInvalidEscape;\n                        goto error;\n                    }\n                }\n\n                // First check for index: all of characters are digit\n                if (c < '0' || c > '9')\n                    isNumber = false;\n\n                *name++ = c;\n            }\n            token->length = static_cast<SizeType>(name - token->name);\n            if (token->length == 0)\n                isNumber = false;\n            *name++ = '\\0'; // Null terminator\n\n            // Second check for index: more than one digit cannot have leading zero\n            if (isNumber && token->length > 1 && token->name[0] == '0')\n                isNumber = false;\n\n            // String to SizeType conversion\n            SizeType n = 0;\n            if (isNumber) {\n                for (size_t j = 0; j < token->length; j++) {\n                    SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');\n                    if (m < n) {   // overflow detection\n                        isNumber = false;\n                        break;\n                    }\n                    n = m;\n                }\n            }\n\n            token->index = isNumber ? n : kPointerInvalidIndex;\n            token++;\n        }\n\n        RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer\n        parseErrorCode_ = kPointerParseErrorNone;\n        return;\n\n    error:\n        Allocator::Free(tokens_);\n        nameBuffer_ = 0;\n        tokens_ = 0;\n        tokenCount_ = 0;\n        parseErrorOffset_ = i;\n        return;\n    }\n\n    //! Stringify to string or URI fragment representation.\n    /*!\n        \\tparam uriFragment True for stringifying to URI fragment representation. False for string representation.\n        \\tparam OutputStream type of output stream.\n        \\param os The output stream.\n    */\n    template<bool uriFragment, typename OutputStream>\n    bool Stringify(OutputStream& os) const {\n        RAPIDJSON_ASSERT(IsValid());\n\n        if (uriFragment)\n            os.Put('#');\n\n        for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            os.Put('/');\n            for (size_t j = 0; j < t->length; j++) {\n                Ch c = t->name[j];\n                if (c == '~') {\n                    os.Put('~');\n                    os.Put('0');\n                }\n                else if (c == '/') {\n                    os.Put('~');\n                    os.Put('1');\n                }\n                else if (uriFragment && NeedPercentEncode(c)) { \n                    // Transcode to UTF8 sequence\n                    GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);\n                    PercentEncodeStream<OutputStream> target(os);\n                    if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))\n                        return false;\n                    j += source.Tell() - 1;\n                }\n                else\n                    os.Put(c);\n            }\n        }\n        return true;\n    }\n\n    //! A helper stream for decoding a percent-encoded sequence into code unit.\n    /*!\n        This stream decodes %XY triplet into code unit (0-255).\n        If it encounters invalid characters, it sets output code unit as 0 and \n        mark invalid, and to be checked by IsValid().\n    */\n    class PercentDecodeStream {\n    public:\n        typedef typename ValueType::Ch Ch;\n\n        //! Constructor\n        /*!\n            \\param source Start of the stream\n            \\param end Past-the-end of the stream.\n        */\n        PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}\n\n        Ch Take() {\n            if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet\n                valid_ = false;\n                return 0;\n            }\n            src_++;\n            Ch c = 0;\n            for (int j = 0; j < 2; j++) {\n                c = static_cast<Ch>(c << 4);\n                Ch h = *src_;\n                if      (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');\n                else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);\n                else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);\n                else {\n                    valid_ = false;\n                    return 0;\n                }\n                src_++;\n            }\n            return c;\n        }\n\n        size_t Tell() const { return static_cast<size_t>(src_ - head_); }\n        bool IsValid() const { return valid_; }\n\n    private:\n        const Ch* src_;     //!< Current read position.\n        const Ch* head_;    //!< Original head of the string.\n        const Ch* end_;     //!< Past-the-end position.\n        bool valid_;        //!< Whether the parsing is valid.\n    };\n\n    //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.\n    template <typename OutputStream>\n    class PercentEncodeStream {\n    public:\n        PercentEncodeStream(OutputStream& os) : os_(os) {}\n        void Put(char c) { // UTF-8 must be byte\n            unsigned char u = static_cast<unsigned char>(c);\n            static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n            os_.Put('%');\n            os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));\n            os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));\n        }\n    private:\n        OutputStream& os_;\n    };\n\n    Allocator* allocator_;                  //!< The current allocator. It is either user-supplied or equal to ownAllocator_.\n    Allocator* ownAllocator_;               //!< Allocator owned by this Pointer.\n    Ch* nameBuffer_;                        //!< A buffer containing all names in tokens.\n    Token* tokens_;                         //!< A list of tokens.\n    size_t tokenCount_;                     //!< Number of tokens in tokens_.\n    size_t parseErrorOffset_;               //!< Offset in code unit when parsing fail.\n    PointerParseErrorCode parseErrorCode_;  //!< Parsing error code.\n};\n\n//! GenericPointer for Value (UTF-8, default allocator).\ntypedef GenericPointer<Value> Pointer;\n\n//!@name Helper functions for GenericPointer\n//@{\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {\n    return pointer.Create(root, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {\n    return pointer.Create(document);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {\n    return pointer.Get(root, unresolvedTokenIndex);\n}\n\ntemplate <typename T>\nconst typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {\n    return pointer.Get(root, unresolvedTokenIndex);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);\n}\n\ntemplate <typename T, typename CharType, size_t N>\nconst typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n#endif\n\ntemplate <typename T, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nGetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n#endif\n\ntemplate <typename T, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nGetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n#endif\n\ntemplate <typename DocumentType, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nGetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n#endif\n\ntemplate <typename DocumentType, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nGetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n#endif\n\ntemplate <typename T, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nSetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n#endif\n\ntemplate <typename T, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nSetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {\n    return pointer.Set(document, value);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {\n    return pointer.Set(document, value);\n}\n#endif\n\ntemplate <typename DocumentType, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nSetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n#endif\n\ntemplate <typename DocumentType, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nSetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Swap(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {\n    return pointer.Swap(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\nbool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {\n    return pointer.Erase(root);\n}\n\ntemplate <typename T, typename CharType, size_t N>\nbool EraseValueByPointer(T& root, const CharType(&source)[N]) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);\n}\n\n//@}\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_POINTER_H_\n"
  },
  {
    "path": "src/json/rapidjson/prettywriter.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_PRETTYWRITER_H_\n#define RAPIDJSON_PRETTYWRITER_H_\n\n#include \"writer.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Combination of PrettyWriter format flags.\n/*! \\see PrettyWriter::SetFormatOptions\n */\nenum PrettyFormatOptions {\n    kFormatDefault = 0,         //!< Default pretty formatting.\n    kFormatSingleLineArray = 1  //!< Format arrays on a single line.\n};\n\n//! Writer with indentation and spacing.\n/*!\n    \\tparam OutputStream Type of output os.\n    \\tparam SourceEncoding Encoding of source string.\n    \\tparam TargetEncoding Encoding of output stream.\n    \\tparam StackAllocator Type of allocator for allocating memory of stack.\n*/\ntemplate<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>\nclass PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {\npublic:\n    typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;\n    typedef typename Base::Ch Ch;\n\n    //! Constructor\n    /*! \\param os Output stream.\n        \\param allocator User supplied allocator. If it is null, it will create a private one.\n        \\param levelDepth Initial capacity of stack.\n    */\n    explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : \n        Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}\n\n\n    explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : \n        Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    PrettyWriter(PrettyWriter&& rhs) :\n        Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}\n#endif\n\n    //! Set custom indentation.\n    /*! \\param indentChar       Character for indentation. Must be whitespace character (' ', '\\\\t', '\\\\n', '\\\\r').\n        \\param indentCharCount  Number of indent characters for each indentation level.\n        \\note The default indentation is 4 spaces.\n    */\n    PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {\n        RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\\t' || indentChar == '\\n' || indentChar == '\\r');\n        indentChar_ = indentChar;\n        indentCharCount_ = indentCharCount;\n        return *this;\n    }\n\n    //! Set pretty writer formatting options.\n    /*! \\param options Formatting options.\n    */\n    PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {\n        formatOptions_ = options;\n        return *this;\n    }\n\n    /*! @name Implementation of Handler\n        \\see Handler\n    */\n    //@{\n\n    bool Null()                 { PrettyPrefix(kNullType);   return Base::EndValue(Base::WriteNull()); }\n    bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }\n    bool Int(int i)             { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }\n    bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }\n    bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }\n    bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64));  }\n    bool Double(double d)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }\n\n    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {\n        RAPIDJSON_ASSERT(str != 0);\n        (void)copy;\n        PrettyPrefix(kNumberType);\n        return Base::EndValue(Base::WriteString(str, length));\n    }\n\n    bool String(const Ch* str, SizeType length, bool copy = false) {\n        RAPIDJSON_ASSERT(str != 0);\n        (void)copy;\n        PrettyPrefix(kStringType);\n        return Base::EndValue(Base::WriteString(str, length));\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool String(const std::basic_string<Ch>& str) {\n        return String(str.data(), SizeType(str.size()));\n    }\n#endif\n\n    bool StartObject() {\n        PrettyPrefix(kObjectType);\n        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);\n        return Base::WriteStartObject();\n    }\n\n    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool Key(const std::basic_string<Ch>& str) {\n        return Key(str.data(), SizeType(str.size()));\n    }\n#endif\n\t\n    bool EndObject(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object\n        RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object\n        RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value\n       \n        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n        if (!empty) {\n            Base::os_->Put('\\n');\n            WriteIndent();\n        }\n        bool ret = Base::EndValue(Base::WriteEndObject());\n        (void)ret;\n        RAPIDJSON_ASSERT(ret == true);\n        if (Base::level_stack_.Empty()) // end of json text\n            Base::Flush();\n        return true;\n    }\n\n    bool StartArray() {\n        PrettyPrefix(kArrayType);\n        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);\n        return Base::WriteStartArray();\n    }\n\n    bool EndArray(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n        RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);\n        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n        if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {\n            Base::os_->Put('\\n');\n            WriteIndent();\n        }\n        bool ret = Base::EndValue(Base::WriteEndArray());\n        (void)ret;\n        RAPIDJSON_ASSERT(ret == true);\n        if (Base::level_stack_.Empty()) // end of json text\n            Base::Flush();\n        return true;\n    }\n\n    //@}\n\n    /*! @name Convenience extensions */\n    //@{\n\n    //! Simpler but slower overload.\n    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }\n    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }\n\n    //@}\n\n    //! Write a raw JSON value.\n    /*!\n        For user to write a stringified JSON as a value.\n\n        \\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.\n        \\param length Length of the json.\n        \\param type Type of the root of json.\n        \\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.\n    */\n    bool RawValue(const Ch* json, size_t length, Type type) {\n        RAPIDJSON_ASSERT(json != 0);\n        PrettyPrefix(type);\n        return Base::EndValue(Base::WriteRawValue(json, length));\n    }\n\nprotected:\n    void PrettyPrefix(Type type) {\n        (void)type;\n        if (Base::level_stack_.GetSize() != 0) { // this value is not at root\n            typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();\n\n            if (level->inArray) {\n                if (level->valueCount > 0) {\n                    Base::os_->Put(','); // add comma if it is not the first element in array\n                    if (formatOptions_ & kFormatSingleLineArray)\n                        Base::os_->Put(' ');\n                }\n\n                if (!(formatOptions_ & kFormatSingleLineArray)) {\n                    Base::os_->Put('\\n');\n                    WriteIndent();\n                }\n            }\n            else {  // in object\n                if (level->valueCount > 0) {\n                    if (level->valueCount % 2 == 0) {\n                        Base::os_->Put(',');\n                        Base::os_->Put('\\n');\n                    }\n                    else {\n                        Base::os_->Put(':');\n                        Base::os_->Put(' ');\n                    }\n                }\n                else\n                    Base::os_->Put('\\n');\n\n                if (level->valueCount % 2 == 0)\n                    WriteIndent();\n            }\n            if (!level->inArray && level->valueCount % 2 == 0)\n                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n            level->valueCount++;\n        }\n        else {\n            RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.\n            Base::hasRoot_ = true;\n        }\n    }\n\n    void WriteIndent()  {\n        size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;\n        PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);\n    }\n\n    Ch indentChar_;\n    unsigned indentCharCount_;\n    PrettyFormatOptions formatOptions_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    PrettyWriter(const PrettyWriter&);\n    PrettyWriter& operator=(const PrettyWriter&);\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "src/json/rapidjson/rapidjson.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_RAPIDJSON_H_\n#define RAPIDJSON_RAPIDJSON_H_\n\n/*!\\file rapidjson.h\n    \\brief common definitions and configuration\n    \n    \\see RAPIDJSON_CONFIG\n */\n\n/*! \\defgroup RAPIDJSON_CONFIG RapidJSON configuration\n    \\brief Configuration macros for library features\n\n    Some RapidJSON features are configurable to adapt the library to a wide\n    variety of platforms, environments and usage scenarios.  Most of the\n    features can be configured in terms of overridden or predefined\n    preprocessor macros at compile-time.\n\n    Some additional customization is available in the \\ref RAPIDJSON_ERRORS APIs.\n\n    \\note These macros should be given on the compiler command-line\n          (where applicable)  to avoid inconsistent values when compiling\n          different translation units of a single application.\n */\n\n#include <cstdlib>  // malloc(), realloc(), free(), size_t\n#include <cstring>  // memset(), memcpy(), memmove(), memcmp()\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_VERSION_STRING\n//\n// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.\n//\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n// token stringification\n#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)\n#define RAPIDJSON_DO_STRINGIFY(x) #x\n\n// token concatenation\n#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)\n#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)\n#define RAPIDJSON_DO_JOIN2(X, Y) X##Y\n//!@endcond\n\n/*! \\def RAPIDJSON_MAJOR_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Major version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_MINOR_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Minor version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_PATCH_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Patch version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_VERSION_STRING\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Version of RapidJSON in \"<major>.<minor>.<patch>\" string format.\n*/\n#define RAPIDJSON_MAJOR_VERSION 1\n#define RAPIDJSON_MINOR_VERSION 1\n#define RAPIDJSON_PATCH_VERSION 0\n#define RAPIDJSON_VERSION_STRING \\\n    RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NAMESPACE_(BEGIN|END)\n/*! \\def RAPIDJSON_NAMESPACE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace\n\n    In order to avoid symbol clashes and/or \"One Definition Rule\" errors\n    between multiple inclusions of (different versions of) RapidJSON in\n    a single binary, users can customize the name of the main RapidJSON\n    namespace.\n\n    In case of a single nesting level, defining \\c RAPIDJSON_NAMESPACE\n    to a custom name (e.g. \\c MyRapidJSON) is sufficient.  If multiple\n    levels are needed, both \\ref RAPIDJSON_NAMESPACE_BEGIN and \\ref\n    RAPIDJSON_NAMESPACE_END need to be defined as well:\n\n    \\code\n    // in some .cpp file\n    #define RAPIDJSON_NAMESPACE my::rapidjson\n    #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {\n    #define RAPIDJSON_NAMESPACE_END   } }\n    #include \"rapidjson/...\"\n    \\endcode\n\n    \\see rapidjson\n */\n/*! \\def RAPIDJSON_NAMESPACE_BEGIN\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace (opening expression)\n    \\see RAPIDJSON_NAMESPACE\n*/\n/*! \\def RAPIDJSON_NAMESPACE_END\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace (closing expression)\n    \\see RAPIDJSON_NAMESPACE\n*/\n#ifndef RAPIDJSON_NAMESPACE\n#define RAPIDJSON_NAMESPACE rapidjson\n#endif\n#ifndef RAPIDJSON_NAMESPACE_BEGIN\n#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {\n#endif\n#ifndef RAPIDJSON_NAMESPACE_END\n#define RAPIDJSON_NAMESPACE_END }\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_HAS_STDSTRING\n\n#ifndef RAPIDJSON_HAS_STDSTRING\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation\n#else\n#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default\n#endif\n/*! \\def RAPIDJSON_HAS_STDSTRING\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Enable RapidJSON support for \\c std::string\n\n    By defining this preprocessor symbol to \\c 1, several convenience functions for using\n    \\ref rapidjson::GenericValue with \\c std::string are enabled, especially\n    for construction and comparison.\n\n    \\hideinitializer\n*/\n#endif // !defined(RAPIDJSON_HAS_STDSTRING)\n\n#if RAPIDJSON_HAS_STDSTRING\n#include <string>\n#endif // RAPIDJSON_HAS_STDSTRING\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_INT64DEFINE\n\n/*! \\def RAPIDJSON_NO_INT64DEFINE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Use external 64-bit integer types.\n\n    RapidJSON requires the 64-bit integer types \\c int64_t and  \\c uint64_t types\n    to be available at global scope.\n\n    If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to\n    prevent RapidJSON from defining its own types.\n*/\n#ifndef RAPIDJSON_NO_INT64DEFINE\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\t// Visual Studio 2013\n#include \"msinttypes/stdint.h\"\n#include \"msinttypes/inttypes.h\"\n#else\n// Other compilers should have this.\n#include <stdint.h>\n#include <inttypes.h>\n#endif\n//!@endcond\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_NO_INT64DEFINE\n#endif\n#endif // RAPIDJSON_NO_INT64TYPEDEF\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_FORCEINLINE\n\n#ifndef RAPIDJSON_FORCEINLINE\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#if defined(_MSC_VER) && defined(NDEBUG)\n#define RAPIDJSON_FORCEINLINE __forceinline\n#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)\n#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))\n#else\n#define RAPIDJSON_FORCEINLINE\n#endif\n//!@endcond\n#endif // RAPIDJSON_FORCEINLINE\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ENDIAN\n#define RAPIDJSON_LITTLEENDIAN  0   //!< Little endian machine\n#define RAPIDJSON_BIGENDIAN     1   //!< Big endian machine\n\n//! Endianness of the machine.\n/*!\n    \\def RAPIDJSON_ENDIAN\n    \\ingroup RAPIDJSON_CONFIG\n\n    GCC 4.6 provided macro for detecting endianness of the target machine. But other\n    compilers may not have this. User can define RAPIDJSON_ENDIAN to either\n    \\ref RAPIDJSON_LITTLEENDIAN or \\ref RAPIDJSON_BIGENDIAN.\n\n    Default detection implemented with reference to\n    \\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html\n    \\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp\n*/\n#ifndef RAPIDJSON_ENDIAN\n// Detect with GCC 4.6's macro\n#  ifdef __BYTE_ORDER__\n#    if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#    elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#    else\n#      error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.\n#    endif // __BYTE_ORDER__\n// Detect with GLIBC's endian.h\n#  elif defined(__GLIBC__)\n#    include <endian.h>\n#    if (__BYTE_ORDER == __LITTLE_ENDIAN)\n#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#    elif (__BYTE_ORDER == __BIG_ENDIAN)\n#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#    else\n#      error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.\n#   endif // __GLIBC__\n// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro\n#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n// Detect with architecture macros\n#  elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#  elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(RAPIDJSON_DOXYGEN_RUNNING)\n#    define RAPIDJSON_ENDIAN\n#  else\n#    error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.   \n#  endif\n#endif // RAPIDJSON_ENDIAN\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_64BIT\n\n//! Whether using 64-bit architecture\n#ifndef RAPIDJSON_64BIT\n#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)\n#define RAPIDJSON_64BIT 1\n#else\n#define RAPIDJSON_64BIT 0\n#endif\n#endif // RAPIDJSON_64BIT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ALIGN\n\n//! Data alignment of the machine.\n/*! \\ingroup RAPIDJSON_CONFIG\n    \\param x pointer to align\n\n    Some machines require strict data alignment. The default is 8 bytes.\n    User can customize by defining the RAPIDJSON_ALIGN function macro.\n*/\n#ifndef RAPIDJSON_ALIGN\n#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_UINT64_C2\n\n//! Construct a 64-bit literal by a pair of 32-bit integer.\n/*!\n    64-bit literal with or without ULL suffix is prone to compiler warnings.\n    UINT64_C() is C macro which cause compilation problems.\n    Use this macro to define 64-bit constants by a pair of 32-bit integer.\n*/\n#ifndef RAPIDJSON_UINT64_C2\n#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_48BITPOINTER_OPTIMIZATION\n\n//! Use only lower 48-bit address for some pointers.\n/*!\n    \\ingroup RAPIDJSON_CONFIG\n\n    This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.\n    The higher 16-bit can be used for storing other data.\n    \\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.\n*/\n#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION\n#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)\n#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1\n#else\n#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0\n#endif\n#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION\n\n#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1\n#if RAPIDJSON_64BIT != 1\n#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1\n#endif\n#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))\n#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))\n#else\n#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))\n#define RAPIDJSON_GETPOINTER(type, p) (p)\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD\n\n/*! \\def RAPIDJSON_SIMD\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Enable SSE2/SSE4.2/Neon optimization.\n\n    RapidJSON supports optimized implementations for some parsing operations\n    based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel\n    or ARM compatible processors.\n\n    To enable these optimizations, three different symbols can be defined;\n    \\code\n    // Enable SSE2 optimization.\n    #define RAPIDJSON_SSE2\n\n    // Enable SSE4.2 optimization.\n    #define RAPIDJSON_SSE42\n    \\endcode\n\n    // Enable ARM Neon optimization.\n    #define RAPIDJSON_NEON\n    \\endcode\n\n    \\c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.\n\n    If any of these symbols is defined, RapidJSON defines the macro\n    \\c RAPIDJSON_SIMD to indicate the availability of the optimized code.\n*/\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \\\n    || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)\n#define RAPIDJSON_SIMD\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_SIZETYPEDEFINE\n\n#ifndef RAPIDJSON_NO_SIZETYPEDEFINE\n/*! \\def RAPIDJSON_NO_SIZETYPEDEFINE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-provided \\c SizeType definition.\n\n    In order to avoid using 32-bit size types for indexing strings and arrays,\n    define this preprocessor symbol and provide the type rapidjson::SizeType\n    before including RapidJSON:\n    \\code\n    #define RAPIDJSON_NO_SIZETYPEDEFINE\n    namespace rapidjson { typedef ::std::size_t SizeType; }\n    #include \"rapidjson/...\"\n    \\endcode\n\n    \\see rapidjson::SizeType\n*/\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_NO_SIZETYPEDEFINE\n#endif\nRAPIDJSON_NAMESPACE_BEGIN\n//! Size type (for string lengths, array sizes, etc.)\n/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,\n    instead of using \\c size_t. Users may override the SizeType by defining\n    \\ref RAPIDJSON_NO_SIZETYPEDEFINE.\n*/\ntypedef unsigned SizeType;\nRAPIDJSON_NAMESPACE_END\n#endif\n\n// always import std::size_t to rapidjson namespace\nRAPIDJSON_NAMESPACE_BEGIN\nusing std::size_t;\nRAPIDJSON_NAMESPACE_END\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ASSERT\n\n//! Assertion.\n/*! \\ingroup RAPIDJSON_CONFIG\n    By default, rapidjson uses C \\c assert() for internal assertions.\n    User can override it by defining RAPIDJSON_ASSERT(x) macro.\n\n    \\note Parsing errors are handled and can be customized by the\n          \\ref RAPIDJSON_ERRORS APIs.\n*/\n#ifndef RAPIDJSON_ASSERT\n#include <cassert>\n#define RAPIDJSON_ASSERT(x) assert(x)\n#endif // RAPIDJSON_ASSERT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_STATIC_ASSERT\n\n// Prefer C++11 static_assert, if available\n#ifndef RAPIDJSON_STATIC_ASSERT\n#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )\n#define RAPIDJSON_STATIC_ASSERT(x) \\\n   static_assert(x, RAPIDJSON_STRINGIFY(x))\n#endif // C++11\n#endif // RAPIDJSON_STATIC_ASSERT\n\n// Adopt C++03 implementation from boost\n#ifndef RAPIDJSON_STATIC_ASSERT\n#ifndef __clang__\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#endif\nRAPIDJSON_NAMESPACE_BEGIN\ntemplate <bool x> struct STATIC_ASSERTION_FAILURE;\ntemplate <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };\ntemplate <size_t x> struct StaticAssertTest {};\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__GNUC__) || defined(__clang__)\n#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))\n#else\n#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE \n#endif\n#ifndef __clang__\n//!@endcond\n#endif\n\n/*! \\def RAPIDJSON_STATIC_ASSERT\n    \\brief (Internal) macro to check for conditions at compile-time\n    \\param x compile-time condition\n    \\hideinitializer\n */\n#define RAPIDJSON_STATIC_ASSERT(x) \\\n    typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \\\n      sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \\\n    RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE\n#endif // RAPIDJSON_STATIC_ASSERT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY\n\n//! Compiler branching hint for expression with high probability to be true.\n/*!\n    \\ingroup RAPIDJSON_CONFIG\n    \\param x Boolean expression likely to be true.\n*/\n#ifndef RAPIDJSON_LIKELY\n#if defined(__GNUC__) || defined(__clang__)\n#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)\n#else\n#define RAPIDJSON_LIKELY(x) (x)\n#endif\n#endif\n\n//! Compiler branching hint for expression with low probability to be true.\n/*!\n    \\ingroup RAPIDJSON_CONFIG\n    \\param x Boolean expression unlikely to be true.\n*/\n#ifndef RAPIDJSON_UNLIKELY\n#if defined(__GNUC__) || defined(__clang__)\n#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)\n#else\n#define RAPIDJSON_UNLIKELY(x) (x)\n#endif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// Helpers\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n\n#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  \n#define RAPIDJSON_MULTILINEMACRO_END \\\n} while((void)0, 0)\n\n// adopted from Boost\n#define RAPIDJSON_VERSION_CODE(x,y,z) \\\n  (((x)*100000) + ((y)*100) + (z))\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF\n\n#if defined(__GNUC__)\n#define RAPIDJSON_GNUC \\\n    RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)\n#endif\n\n#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))\n\n#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))\n#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)\n#define RAPIDJSON_DIAG_OFF(x) \\\n    RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))\n\n// push/pop support in Clang and GCC>=4.6\n#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))\n#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)\n#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)\n#else // GCC >= 4.2, < 4.6\n#define RAPIDJSON_DIAG_PUSH /* ignored */\n#define RAPIDJSON_DIAG_POP /* ignored */\n#endif\n\n#elif defined(_MSC_VER)\n\n// pragma (MSVC specific)\n#define RAPIDJSON_PRAGMA(x) __pragma(x)\n#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))\n\n#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)\n#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)\n#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)\n\n#else\n\n#define RAPIDJSON_DIAG_OFF(x) /* ignored */\n#define RAPIDJSON_DIAG_PUSH   /* ignored */\n#define RAPIDJSON_DIAG_POP    /* ignored */\n\n#endif // RAPIDJSON_DIAG_*\n\n///////////////////////////////////////////////////////////////////////////////\n// C++11 features\n\n#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#if defined(__clang__)\n#if __has_feature(cxx_rvalue_references) && \\\n    (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1\n#else\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0\n#endif\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \\\n      (defined(_MSC_VER) && _MSC_VER >= 1600) || \\\n      (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))\n\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1\n#else\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0\n#endif\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT\n#if defined(__clang__)\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \\\n    (defined(_MSC_VER) && _MSC_VER >= 1900) || \\\n    (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1\n#else\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0\n#endif\n#endif\n#if RAPIDJSON_HAS_CXX11_NOEXCEPT\n#define RAPIDJSON_NOEXCEPT noexcept\n#else\n#define RAPIDJSON_NOEXCEPT /* noexcept */\n#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT\n\n// no automatic detection, yet\n#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS\n#if (defined(_MSC_VER) && _MSC_VER >= 1700)\n#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1\n#else\n#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0\n#endif\n#endif\n\n#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR\n#if defined(__clang__)\n#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \\\n      (defined(_MSC_VER) && _MSC_VER >= 1700) || \\\n      (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))\n#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1\n#else\n#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0\n#endif\n#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR\n\n//!@endcond\n\n//! Assertion (in non-throwing contexts).\n /*! \\ingroup RAPIDJSON_CONFIG\n    Some functions provide a \\c noexcept guarantee, if the compiler supports it.\n    In these cases, the \\ref RAPIDJSON_ASSERT macro cannot be overridden to\n    throw an exception.  This macro adds a separate customization point for\n    such cases.\n\n    Defaults to C \\c assert() (as \\ref RAPIDJSON_ASSERT), if \\c noexcept is\n    supported, and to \\ref RAPIDJSON_ASSERT otherwise.\n */\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NOEXCEPT_ASSERT\n\n#ifndef RAPIDJSON_NOEXCEPT_ASSERT\n#ifdef RAPIDJSON_ASSERT_THROWS\n#if RAPIDJSON_HAS_CXX11_NOEXCEPT\n#define RAPIDJSON_NOEXCEPT_ASSERT(x)\n#else\n#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)\n#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT\n#else\n#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)\n#endif // RAPIDJSON_ASSERT_THROWS\n#endif // RAPIDJSON_NOEXCEPT_ASSERT\n\n///////////////////////////////////////////////////////////////////////////////\n// new/delete\n\n#ifndef RAPIDJSON_NEW\n///! customization point for global \\c new\n#define RAPIDJSON_NEW(TypeName) new TypeName\n#endif\n#ifndef RAPIDJSON_DELETE\n///! customization point for global \\c delete\n#define RAPIDJSON_DELETE(x) delete x\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// Type\n\n/*! \\namespace rapidjson\n    \\brief main RapidJSON namespace\n    \\see RAPIDJSON_NAMESPACE\n*/\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Type of JSON value\nenum Type {\n    kNullType = 0,      //!< null\n    kFalseType = 1,     //!< false\n    kTrueType = 2,      //!< true\n    kObjectType = 3,    //!< object\n    kArrayType = 4,     //!< array \n    kStringType = 5,    //!< string\n    kNumberType = 6     //!< number\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "src/json/rapidjson/reader.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_READER_H_\n#define RAPIDJSON_READER_H_\n\n/*! \\file reader.h */\n\n#include \"allocators.h\"\n#include \"stream.h\"\n#include \"encodedstream.h\"\n#include \"src/json/rapidjson/internal/meta.h\"\n#include \"src/json/rapidjson/internal/stack.h\"\n#include \"src/json/rapidjson/internal/strtod.h\"\n#include <limits>\n\n#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)\n#include <intrin.h>\n#pragma intrinsic(_BitScanForward)\n#endif\n#ifdef RAPIDJSON_SSE42\n#include <nmmintrin.h>\n#elif defined(RAPIDJSON_SSE2)\n#include <emmintrin.h>\n#elif defined(RAPIDJSON_NEON)\n#include <arm_neon.h>\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(old-style-cast)\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(switch-enum)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127)  // conditional expression is constant\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define RAPIDJSON_NOTHING /* deliberately empty */\n#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN\n#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \\\n    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)\n//!@endcond\n\n/*! \\def RAPIDJSON_PARSE_ERROR_NORETURN\n    \\ingroup RAPIDJSON_ERRORS\n    \\brief Macro to indicate a parse error.\n    \\param parseErrorCode \\ref rapidjson::ParseErrorCode of the error\n    \\param offset  position of the error in JSON input (\\c size_t)\n\n    This macros can be used as a customization point for the internal\n    error handling mechanism of RapidJSON.\n\n    A common usage model is to throw an exception instead of requiring the\n    caller to explicitly check the \\ref rapidjson::GenericReader::Parse's\n    return value:\n\n    \\code\n    #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \\\n       throw ParseException(parseErrorCode, #parseErrorCode, offset)\n\n    #include <stdexcept>               // std::runtime_error\n    #include \"rapidjson/error/error.h\" // rapidjson::ParseResult\n\n    struct ParseException : std::runtime_error, rapidjson::ParseResult {\n      ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)\n        : std::runtime_error(msg), ParseResult(code, offset) {}\n    };\n\n    #include \"rapidjson/reader.h\"\n    \\endcode\n\n    \\see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse\n */\n#ifndef RAPIDJSON_PARSE_ERROR_NORETURN\n#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \\\n    SetParseError(parseErrorCode, offset); \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n\n/*! \\def RAPIDJSON_PARSE_ERROR\n    \\ingroup RAPIDJSON_ERRORS\n    \\brief (Internal) macro to indicate and handle a parse error.\n    \\param parseErrorCode \\ref rapidjson::ParseErrorCode of the error\n    \\param offset  position of the error in JSON input (\\c size_t)\n\n    Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.\n\n    \\see RAPIDJSON_PARSE_ERROR_NORETURN\n    \\hideinitializer\n */\n#ifndef RAPIDJSON_PARSE_ERROR\n#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \\\n    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n\n#include \"src/json/rapidjson/error/error.h\" // ParseErrorCode, ParseResult\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseFlag\n\n/*! \\def RAPIDJSON_PARSE_DEFAULT_FLAGS\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-defined kParseDefaultFlags definition.\n\n    User can define this as any \\c ParseFlag combinations.\n*/\n#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS\n#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags\n#endif\n\n//! Combination of parseFlags\n/*! \\see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream\n */\nenum ParseFlag {\n    kParseNoFlags = 0,              //!< No flags are set.\n    kParseInsituFlag = 1,           //!< In-situ(destructive) parsing.\n    kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.\n    kParseIterativeFlag = 4,        //!< Iterative(constant complexity in terms of function call stack size) parsing.\n    kParseStopWhenDoneFlag = 8,     //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.\n    kParseFullPrecisionFlag = 16,   //!< Parse number in full precision (but slower).\n    kParseCommentsFlag = 32,        //!< Allow one-line (//) and multi-line (/**/) comments.\n    kParseNumbersAsStringsFlag = 64,    //!< Parse all numbers (ints/doubles) as strings.\n    kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.\n    kParseNanAndInfFlag = 256,      //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.\n    kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS  //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Handler\n\n/*! \\class rapidjson::Handler\n    \\brief Concept for receiving events from GenericReader upon parsing.\n    The functions return true if no error occurs. If they return false,\n    the event publisher should terminate the process.\n\\code\nconcept Handler {\n    typename Ch;\n\n    bool Null();\n    bool Bool(bool b);\n    bool Int(int i);\n    bool Uint(unsigned i);\n    bool Int64(int64_t i);\n    bool Uint64(uint64_t i);\n    bool Double(double d);\n    /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)\n    bool RawNumber(const Ch* str, SizeType length, bool copy);\n    bool String(const Ch* str, SizeType length, bool copy);\n    bool StartObject();\n    bool Key(const Ch* str, SizeType length, bool copy);\n    bool EndObject(SizeType memberCount);\n    bool StartArray();\n    bool EndArray(SizeType elementCount);\n};\n\\endcode\n*/\n///////////////////////////////////////////////////////////////////////////////\n// BaseReaderHandler\n\n//! Default implementation of Handler.\n/*! This can be used as base class of any reader handler.\n    \\note implements Handler concept\n*/\ntemplate<typename Encoding = UTF8<>, typename Derived = void>\nstruct BaseReaderHandler {\n    typedef typename Encoding::Ch Ch;\n\n    typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;\n\n    bool Default() { return true; }\n    bool Null() { return static_cast<Override&>(*this).Default(); }\n    bool Bool(bool) { return static_cast<Override&>(*this).Default(); }\n    bool Int(int) { return static_cast<Override&>(*this).Default(); }\n    bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }\n    bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }\n    bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }\n    bool Double(double) { return static_cast<Override&>(*this).Default(); }\n    /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)\n    bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }\n    bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }\n    bool StartObject() { return static_cast<Override&>(*this).Default(); }\n    bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }\n    bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }\n    bool StartArray() { return static_cast<Override&>(*this).Default(); }\n    bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// StreamLocalCopy\n\nnamespace internal {\n\ntemplate<typename Stream, int = StreamTraits<Stream>::copyOptimization>\nclass StreamLocalCopy;\n\n//! Do copy optimization.\ntemplate<typename Stream>\nclass StreamLocalCopy<Stream, 1> {\npublic:\n    StreamLocalCopy(Stream& original) : s(original), original_(original) {}\n    ~StreamLocalCopy() { original_ = s; }\n\n    Stream s;\n\nprivate:\n    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;\n\n    Stream& original_;\n};\n\n//! Keep reference.\ntemplate<typename Stream>\nclass StreamLocalCopy<Stream, 0> {\npublic:\n    StreamLocalCopy(Stream& original) : s(original) {}\n\n    Stream& s;\n\nprivate:\n    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;\n};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// SkipWhitespace\n\n//! Skip the JSON white spaces in a stream.\n/*! \\param is A input stream for skipping white spaces.\n    \\note This function has SSE2/SSE4.2 specialization.\n*/\ntemplate<typename InputStream>\nvoid SkipWhitespace(InputStream& is) {\n    internal::StreamLocalCopy<InputStream> copy(is);\n    InputStream& s(copy.s);\n\n    typename InputStream::Ch c;\n    while ((c = s.Peek()) == ' ' || c == '\\n' || c == '\\r' || c == '\\t')\n        s.Take();\n}\n\ninline const char* SkipWhitespace(const char* p, const char* end) {\n    while (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    return p;\n}\n\n#ifdef RAPIDJSON_SSE42\n//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    // The rest of string using SIMD\n    static const char whitespace[16] = \" \\n\\r\\t\";\n    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));\n\n    for (;; p += 16) {\n        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n        const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);\n        if (r != 16)    // some of characters is non-whitespace\n            return p + r;\n    }\n}\n\ninline const char *SkipWhitespace_SIMD(const char* p, const char* end) {\n    // Fast return for single non-whitespace\n    if (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    else\n        return p;\n\n    // The middle of string using SIMD\n    static const char whitespace[16] = \" \\n\\r\\t\";\n    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));\n\n    for (; p <= end - 16; p += 16) {\n        const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));\n        const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);\n        if (r != 16)    // some of characters is non-whitespace\n            return p + r;\n    }\n\n    return SkipWhitespace(p, end);\n}\n\n#elif defined(RAPIDJSON_SSE2)\n\n//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    // The rest of string\n    #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }\n    static const char whitespaces[4][16] = { C16(' '), C16('\\n'), C16('\\r'), C16('\\t') };\n    #undef C16\n\n    const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));\n    const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));\n    const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));\n    const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));\n\n    for (;; p += 16) {\n        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n        __m128i x = _mm_cmpeq_epi8(s, w0);\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));\n        unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));\n        if (r != 0) {   // some of characters may be non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n}\n\ninline const char *SkipWhitespace_SIMD(const char* p, const char* end) {\n    // Fast return for single non-whitespace\n    if (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    else\n        return p;\n\n    // The rest of string\n    #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }\n    static const char whitespaces[4][16] = { C16(' '), C16('\\n'), C16('\\r'), C16('\\t') };\n    #undef C16\n\n    const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));\n    const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));\n    const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));\n    const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));\n\n    for (; p <= end - 16; p += 16) {\n        const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));\n        __m128i x = _mm_cmpeq_epi8(s, w0);\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));\n        unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));\n        if (r != 0) {   // some of characters may be non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n\n    return SkipWhitespace(p, end);\n}\n\n#elif defined(RAPIDJSON_NEON)\n\n//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    const uint8x16_t w0 = vmovq_n_u8(' ');\n    const uint8x16_t w1 = vmovq_n_u8('\\n');\n    const uint8x16_t w2 = vmovq_n_u8('\\r');\n    const uint8x16_t w3 = vmovq_n_u8('\\t');\n\n    for (;; p += 16) {\n        const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));\n        uint8x16_t x = vceqq_u8(s, w0);\n        x = vorrq_u8(x, vceqq_u8(s, w1));\n        x = vorrq_u8(x, vceqq_u8(s, w2));\n        x = vorrq_u8(x, vceqq_u8(s, w3));\n\n        x = vmvnq_u8(x);                       // Negate\n        x = vrev64q_u8(x);                     // Rev in 64\n        uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract\n        uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract\n\n        if (low == 0) {\n            if (high != 0) {\n                int lz =__builtin_clzll(high);;\n                return p + 8 + (lz >> 3);\n            }\n        } else {\n            int lz = __builtin_clzll(low);;\n            return p + (lz >> 3);\n        }\n    }\n}\n\ninline const char *SkipWhitespace_SIMD(const char* p, const char* end) {\n    // Fast return for single non-whitespace\n    if (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    else\n        return p;\n\n    const uint8x16_t w0 = vmovq_n_u8(' ');\n    const uint8x16_t w1 = vmovq_n_u8('\\n');\n    const uint8x16_t w2 = vmovq_n_u8('\\r');\n    const uint8x16_t w3 = vmovq_n_u8('\\t');\n\n    for (; p <= end - 16; p += 16) {\n        const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));\n        uint8x16_t x = vceqq_u8(s, w0);\n        x = vorrq_u8(x, vceqq_u8(s, w1));\n        x = vorrq_u8(x, vceqq_u8(s, w2));\n        x = vorrq_u8(x, vceqq_u8(s, w3));\n\n        x = vmvnq_u8(x);                       // Negate\n        x = vrev64q_u8(x);                     // Rev in 64\n        uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract\n        uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract\n\n        if (low == 0) {\n            if (high != 0) {\n                int lz = __builtin_clzll(high);\n                return p + 8 + (lz >> 3);\n            }\n        } else {\n            int lz = __builtin_clzll(low);\n            return p + (lz >> 3);\n        }\n    }\n\n    return SkipWhitespace(p, end);\n}\n\n#endif // RAPIDJSON_NEON\n\n#ifdef RAPIDJSON_SIMD\n//! Template function specialization for InsituStringStream\ntemplate<> inline void SkipWhitespace(InsituStringStream& is) {\n    is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));\n}\n\n//! Template function specialization for StringStream\ntemplate<> inline void SkipWhitespace(StringStream& is) {\n    is.src_ = SkipWhitespace_SIMD(is.src_);\n}\n\ntemplate<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {\n    is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);\n}\n#endif // RAPIDJSON_SIMD\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericReader\n\n//! SAX-style JSON parser. Use \\ref Reader for UTF8 encoding and default allocator.\n/*! GenericReader parses JSON text from a stream, and send events synchronously to an\n    object implementing Handler concept.\n\n    It needs to allocate a stack for storing a single decoded string during\n    non-destructive parsing.\n\n    For in-situ parsing, the decoded string is directly written to the source\n    text string, no temporary buffer is required.\n\n    A GenericReader object can be reused for parsing multiple JSON text.\n\n    \\tparam SourceEncoding Encoding of the input stream.\n    \\tparam TargetEncoding Encoding of the parse output.\n    \\tparam StackAllocator Allocator type for stack.\n*/\ntemplate <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>\nclass GenericReader {\npublic:\n    typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type\n\n    //! Constructor.\n    /*! \\param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)\n        \\param stackCapacity stack capacity in bytes for storing a single decoded string.  (Only use for non-destructive parsing)\n    */\n    GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) :\n        stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}\n\n    //! Parse JSON text.\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam InputStream Type of input stream, implementing Stream concept.\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n    */\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    ParseResult Parse(InputStream& is, Handler& handler) {\n        if (parseFlags & kParseIterativeFlag)\n            return IterativeParse<parseFlags>(is, handler);\n\n        parseResult_.Clear();\n\n        ClearStackOnExit scope(*this);\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n        if (RAPIDJSON_UNLIKELY(is.Peek() == '\\0')) {\n            RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        }\n        else {\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n            if (!(parseFlags & kParseStopWhenDoneFlag)) {\n                SkipWhitespaceAndComments<parseFlags>(is);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n                if (RAPIDJSON_UNLIKELY(is.Peek() != '\\0')) {\n                    RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n                }\n            }\n        }\n\n        return parseResult_;\n    }\n\n    //! Parse JSON text (with \\ref kParseDefaultFlags)\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n    */\n    template <typename InputStream, typename Handler>\n    ParseResult Parse(InputStream& is, Handler& handler) {\n        return Parse<kParseDefaultFlags>(is, handler);\n    }\n\n    //! Initialize JSON text token-by-token parsing\n    /*!\n     */\n    void IterativeParseInit() {\n        parseResult_.Clear();\n        state_ = IterativeParsingStartState;\n    }\n\n    //! Parse one token from JSON text\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n     */\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    bool IterativeParseNext(InputStream& is, Handler& handler) {\n        while (RAPIDJSON_LIKELY(is.Peek() != '\\0')) {\n            SkipWhitespaceAndComments<parseFlags>(is);\n\n            Token t = Tokenize(is.Peek());\n            IterativeParsingState n = Predict(state_, t);\n            IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler);\n\n            // If we've finished or hit an error...\n            if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) {\n                // Report errors.\n                if (d == IterativeParsingErrorState) {\n                    HandleError(state_, is);\n                    return false;\n                }\n\n                // Transition to the finish state.\n                RAPIDJSON_ASSERT(d == IterativeParsingFinishState);\n                state_ = d;\n\n                // If StopWhenDone is not set...\n                if (!(parseFlags & kParseStopWhenDoneFlag)) {\n                    // ... and extra non-whitespace data is found...\n                    SkipWhitespaceAndComments<parseFlags>(is);\n                    if (is.Peek() != '\\0') {\n                        // ... this is considered an error.\n                        HandleError(state_, is);\n                        return false;\n                    }\n                }\n\n                // Success! We are done!\n                return true;\n            }\n\n            // Transition to the new state.\n            state_ = d;\n\n            // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now.\n            if (!IsIterativeParsingDelimiterState(n))\n                return true;\n        }\n\n        // We reached the end of file.\n        stack_.Clear();\n\n        if (state_ != IterativeParsingFinishState) {\n            HandleError(state_, is);\n            return false;\n        }\n\n        return true;\n    }\n\n    //! Check if token-by-token parsing JSON text is complete\n    /*! \\return Whether the JSON has been fully decoded.\n     */\n    RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const {\n        return IsIterativeParsingCompleteState(state_);\n    }\n\n    //! Whether a parse error has occurred in the last parsing.\n    bool HasParseError() const { return parseResult_.IsError(); }\n\n    //! Get the \\ref ParseErrorCode of last parsing.\n    ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }\n\n    //! Get the position of last parsing error in input, 0 otherwise.\n    size_t GetErrorOffset() const { return parseResult_.Offset(); }\n\nprotected:\n    void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    GenericReader(const GenericReader&);\n    GenericReader& operator=(const GenericReader&);\n\n    void ClearStack() { stack_.Clear(); }\n\n    // clear stack on any exit from ParseStream, e.g. due to exception\n    struct ClearStackOnExit {\n        explicit ClearStackOnExit(GenericReader& r) : r_(r) {}\n        ~ClearStackOnExit() { r_.ClearStack(); }\n    private:\n        GenericReader& r_;\n        ClearStackOnExit(const ClearStackOnExit&);\n        ClearStackOnExit& operator=(const ClearStackOnExit&);\n    };\n\n    template<unsigned parseFlags, typename InputStream>\n    void SkipWhitespaceAndComments(InputStream& is) {\n        SkipWhitespace(is);\n\n        if (parseFlags & kParseCommentsFlag) {\n            while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {\n                if (Consume(is, '*')) {\n                    while (true) {\n                        if (RAPIDJSON_UNLIKELY(is.Peek() == '\\0'))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());\n                        else if (Consume(is, '*')) {\n                            if (Consume(is, '/'))\n                                break;\n                        }\n                        else\n                            is.Take();\n                    }\n                }\n                else if (RAPIDJSON_LIKELY(Consume(is, '/')))\n                    while (is.Peek() != '\\0' && is.Take() != '\\n') {}\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());\n\n                SkipWhitespace(is);\n            }\n        }\n    }\n\n    // Parse object: { string : value, ... }\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseObject(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == '{');\n        is.Take();  // Skip '{'\n\n        if (RAPIDJSON_UNLIKELY(!handler.StartObject()))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n        if (Consume(is, '}')) {\n            if (RAPIDJSON_UNLIKELY(!handler.EndObject(0)))  // empty object\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n            return;\n        }\n\n        for (SizeType memberCount = 0;;) {\n            if (RAPIDJSON_UNLIKELY(is.Peek() != '\"'))\n                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());\n\n            ParseString<parseFlags>(is, handler, true);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))\n                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ++memberCount;\n\n            switch (is.Peek()) {\n                case ',':\n                    is.Take();\n                    SkipWhitespaceAndComments<parseFlags>(is);\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                    break;\n                case '}':\n                    is.Take();\n                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    return;\n                default:\n                    RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy\n            }\n\n            if (parseFlags & kParseTrailingCommasFlag) {\n                if (is.Peek() == '}') {\n                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    is.Take();\n                    return;\n                }\n            }\n        }\n    }\n\n    // Parse array: [ value, ... ]\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseArray(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == '[');\n        is.Take();  // Skip '['\n\n        if (RAPIDJSON_UNLIKELY(!handler.StartArray()))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n        if (Consume(is, ']')) {\n            if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n            return;\n        }\n\n        for (SizeType elementCount = 0;;) {\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ++elementCount;\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            if (Consume(is, ',')) {\n                SkipWhitespaceAndComments<parseFlags>(is);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            }\n            else if (Consume(is, ']')) {\n                if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))\n                    RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                return;\n            }\n            else\n                RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());\n\n            if (parseFlags & kParseTrailingCommasFlag) {\n                if (is.Peek() == ']') {\n                    if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    is.Take();\n                    return;\n                }\n            }\n        }\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseNull(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 'n');\n        is.Take();\n\n        if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {\n            if (RAPIDJSON_UNLIKELY(!handler.Null()))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseTrue(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 't');\n        is.Take();\n\n        if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {\n            if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseFalse(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 'f');\n        is.Take();\n\n        if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {\n            if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());\n    }\n\n    template<typename InputStream>\n    RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {\n        if (RAPIDJSON_LIKELY(is.Peek() == expect)) {\n            is.Take();\n            return true;\n        }\n        else\n            return false;\n    }\n\n    // Helper function to parse four hexadecimal digits in \\uXXXX in ParseString().\n    template<typename InputStream>\n    unsigned ParseHex4(InputStream& is, size_t escapeOffset) {\n        unsigned codepoint = 0;\n        for (int i = 0; i < 4; i++) {\n            Ch c = is.Peek();\n            codepoint <<= 4;\n            codepoint += static_cast<unsigned>(c);\n            if (c >= '0' && c <= '9')\n                codepoint -= '0';\n            else if (c >= 'A' && c <= 'F')\n                codepoint -= 'A' - 10;\n            else if (c >= 'a' && c <= 'f')\n                codepoint -= 'a' - 10;\n            else {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);\n            }\n            is.Take();\n        }\n        return codepoint;\n    }\n\n    template <typename CharType>\n    class StackStream {\n    public:\n        typedef CharType Ch;\n\n        StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}\n        RAPIDJSON_FORCEINLINE void Put(Ch c) {\n            *stack_.template Push<Ch>() = c;\n            ++length_;\n        }\n\n        RAPIDJSON_FORCEINLINE void* Push(SizeType count) {\n            length_ += count;\n            return stack_.template Push<Ch>(count);\n        }\n\n        size_t Length() const { return length_; }\n\n        Ch* Pop() {\n            return stack_.template Pop<Ch>(length_);\n        }\n\n    private:\n        StackStream(const StackStream&);\n        StackStream& operator=(const StackStream&);\n\n        internal::Stack<StackAllocator>& stack_;\n        SizeType length_;\n    };\n\n    // Parse string and generate String event. Different code paths for kParseInsituFlag.\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseString(InputStream& is, Handler& handler, bool isKey = false) {\n        internal::StreamLocalCopy<InputStream> copy(is);\n        InputStream& s(copy.s);\n\n        RAPIDJSON_ASSERT(s.Peek() == '\\\"');\n        s.Take();  // Skip '\\\"'\n\n        bool success = false;\n        if (parseFlags & kParseInsituFlag) {\n            typename InputStream::Ch *head = s.PutBegin();\n            ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            size_t length = s.PutEnd(head) - 1;\n            RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);\n            const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);\n            success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));\n        }\n        else {\n            StackStream<typename TargetEncoding::Ch> stackStream(stack_);\n            ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;\n            const typename TargetEncoding::Ch* const str = stackStream.Pop();\n            success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));\n        }\n        if (RAPIDJSON_UNLIKELY(!success))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());\n    }\n\n    // Parse string to an output is\n    // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.\n    template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n        static const char escape[256] = {\n            Z16, Z16, 0, 0,'\\\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',\n            Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\\\', 0, 0, 0,\n            0, 0,'\\b', 0, 0, 0,'\\f', 0, 0, 0, 0, 0, 0, 0,'\\n', 0,\n            0, 0,'\\r', 0,'\\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16\n        };\n#undef Z16\n//!@endcond\n\n        for (;;) {\n            // Scan and copy string before \"\\\\\\\"\" or < 0x20. This is an optional optimzation.\n            if (!(parseFlags & kParseValidateEncodingFlag))\n                ScanCopyUnescapedString(is, os);\n\n            Ch c = is.Peek();\n            if (RAPIDJSON_UNLIKELY(c == '\\\\')) {    // Escape\n                size_t escapeOffset = is.Tell();    // For invalid escaping, report the initial '\\\\' as error offset\n                is.Take();\n                Ch e = is.Peek();\n                if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {\n                    is.Take();\n                    os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));\n                }\n                else if (RAPIDJSON_LIKELY(e == 'u')) {    // Unicode\n                    is.Take();\n                    unsigned codepoint = ParseHex4(is, escapeOffset);\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                    if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {\n                        // Handle UTF-16 surrogate pair\n                        if (RAPIDJSON_UNLIKELY(!Consume(is, '\\\\') || !Consume(is, 'u')))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);\n                        unsigned codepoint2 = ParseHex4(is, escapeOffset);\n                        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                        if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);\n                        codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;\n                    }\n                    TEncoding::Encode(os, codepoint);\n                }\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);\n            }\n            else if (RAPIDJSON_UNLIKELY(c == '\"')) {    // Closing double quote\n                is.Take();\n                os.Put('\\0');   // null-terminate the string\n                return;\n            }\n            else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF\n                if (c == '\\0')\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());\n            }\n            else {\n                size_t offset = is.Tell();\n                if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?\n                    !Transcoder<SEncoding, TEncoding>::Validate(is, os) :\n                    !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);\n            }\n        }\n    }\n\n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {\n            // Do nothing for generic version\n    }\n\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)\n    // StringStream -> StackStream<char>\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {\n        const char* p = is.src_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        while (p != nextAligned)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = p;\n                return;\n            }\n            else\n                os.Put(*p++);\n\n        // The rest of string using SIMD\n        static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n        static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n        static const char space[16]  = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };\n        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n        for (;; p += 16) {\n            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n            const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n            const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F\n            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n                SizeType length;\n    #ifdef _MSC_VER         // Find the index of first escaped\n                unsigned long offset;\n                _BitScanForward(&offset, r);\n                length = offset;\n    #else\n                length = static_cast<SizeType>(__builtin_ffs(r) - 1);\n    #endif\n                if (length != 0) {\n                    char* q = reinterpret_cast<char*>(os.Push(length));\n                    for (size_t i = 0; i < length; i++)\n                        q[i] = p[i];\n\n                    p += length;\n                }\n                break;\n            }\n            _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);\n        }\n\n        is.src_ = p;\n    }\n\n    // InsituStringStream -> InsituStringStream\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {\n        RAPIDJSON_ASSERT(&is == &os);\n        (void)os;\n\n        if (is.src_ == is.dst_) {\n            SkipUnescapedString(is);\n            return;\n        }\n\n        char* p = is.src_;\n        char *q = is.dst_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        while (p != nextAligned)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = p;\n                is.dst_ = q;\n                return;\n            }\n            else\n                *q++ = *p++;\n\n        // The rest of string using SIMD\n        static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n        static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n        static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };\n        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n        for (;; p += 16, q += 16) {\n            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n            const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n            const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F\n            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n                size_t length;\n#ifdef _MSC_VER         // Find the index of first escaped\n                unsigned long offset;\n                _BitScanForward(&offset, r);\n                length = offset;\n#else\n                length = static_cast<size_t>(__builtin_ffs(r) - 1);\n#endif\n                for (const char* pend = p + length; p != pend; )\n                    *q++ = *p++;\n                break;\n            }\n            _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);\n        }\n\n        is.src_ = p;\n        is.dst_ = q;\n    }\n\n    // When read/write pointers are the same for insitu stream, just skip unescaped characters\n    static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {\n        RAPIDJSON_ASSERT(is.src_ == is.dst_);\n        char* p = is.src_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        for (; p != nextAligned; p++)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = is.dst_ = p;\n                return;\n            }\n\n        // The rest of string using SIMD\n        static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n        static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n        static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };\n        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n        for (;; p += 16) {\n            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n            const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n            const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F\n            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n                size_t length;\n#ifdef _MSC_VER         // Find the index of first escaped\n                unsigned long offset;\n                _BitScanForward(&offset, r);\n                length = offset;\n#else\n                length = static_cast<size_t>(__builtin_ffs(r) - 1);\n#endif\n                p += length;\n                break;\n            }\n        }\n\n        is.src_ = is.dst_ = p;\n    }\n#elif defined(RAPIDJSON_NEON)\n    // StringStream -> StackStream<char>\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {\n        const char* p = is.src_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        while (p != nextAligned)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = p;\n                return;\n            }\n            else\n                os.Put(*p++);\n\n        // The rest of string using SIMD\n        const uint8x16_t s0 = vmovq_n_u8('\"');\n        const uint8x16_t s1 = vmovq_n_u8('\\\\');\n        const uint8x16_t s2 = vmovq_n_u8('\\b');\n        const uint8x16_t s3 = vmovq_n_u8(32);\n\n        for (;; p += 16) {\n            const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));\n            uint8x16_t x = vceqq_u8(s, s0);\n            x = vorrq_u8(x, vceqq_u8(s, s1));\n            x = vorrq_u8(x, vceqq_u8(s, s2));\n            x = vorrq_u8(x, vcltq_u8(s, s3));\n\n            x = vrev64q_u8(x);                     // Rev in 64\n            uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract\n            uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract\n\n            SizeType length = 0;\n            bool escaped = false;\n            if (low == 0) {\n                if (high != 0) {\n                    unsigned lz = (unsigned)__builtin_clzll(high);;\n                    length = 8 + (lz >> 3);\n                    escaped = true;\n                }\n            } else {\n                unsigned lz = (unsigned)__builtin_clzll(low);;\n                length = lz >> 3;\n                escaped = true;\n            }\n            if (RAPIDJSON_UNLIKELY(escaped)) {   // some of characters is escaped\n                if (length != 0) {\n                    char* q = reinterpret_cast<char*>(os.Push(length));\n                    for (size_t i = 0; i < length; i++)\n                        q[i] = p[i];\n\n                    p += length;\n                }\n                break;\n            }\n            vst1q_u8(reinterpret_cast<uint8_t *>(os.Push(16)), s);\n        }\n\n        is.src_ = p;\n    }\n\n    // InsituStringStream -> InsituStringStream\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {\n        RAPIDJSON_ASSERT(&is == &os);\n        (void)os;\n\n        if (is.src_ == is.dst_) {\n            SkipUnescapedString(is);\n            return;\n        }\n\n        char* p = is.src_;\n        char *q = is.dst_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        while (p != nextAligned)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = p;\n                is.dst_ = q;\n                return;\n            }\n            else\n                *q++ = *p++;\n\n        // The rest of string using SIMD\n        const uint8x16_t s0 = vmovq_n_u8('\"');\n        const uint8x16_t s1 = vmovq_n_u8('\\\\');\n        const uint8x16_t s2 = vmovq_n_u8('\\b');\n        const uint8x16_t s3 = vmovq_n_u8(32);\n\n        for (;; p += 16, q += 16) {\n            const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));\n            uint8x16_t x = vceqq_u8(s, s0);\n            x = vorrq_u8(x, vceqq_u8(s, s1));\n            x = vorrq_u8(x, vceqq_u8(s, s2));\n            x = vorrq_u8(x, vcltq_u8(s, s3));\n\n            x = vrev64q_u8(x);                     // Rev in 64\n            uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract\n            uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract\n\n            SizeType length = 0;\n            bool escaped = false;\n            if (low == 0) {\n                if (high != 0) {\n                    unsigned lz = (unsigned)__builtin_clzll(high);\n                    length = 8 + (lz >> 3);\n                    escaped = true;\n                }\n            } else {\n                unsigned lz = (unsigned)__builtin_clzll(low);\n                length = lz >> 3;\n                escaped = true;\n            }\n            if (RAPIDJSON_UNLIKELY(escaped)) {   // some of characters is escaped\n                for (const char* pend = p + length; p != pend; ) {\n                    *q++ = *p++;\n                }\n                break;\n            }\n            vst1q_u8(reinterpret_cast<uint8_t *>(q), s);\n        }\n\n        is.src_ = p;\n        is.dst_ = q;\n    }\n\n    // When read/write pointers are the same for insitu stream, just skip unescaped characters\n    static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {\n        RAPIDJSON_ASSERT(is.src_ == is.dst_);\n        char* p = is.src_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        for (; p != nextAligned; p++)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = is.dst_ = p;\n                return;\n            }\n\n        // The rest of string using SIMD\n        const uint8x16_t s0 = vmovq_n_u8('\"');\n        const uint8x16_t s1 = vmovq_n_u8('\\\\');\n        const uint8x16_t s2 = vmovq_n_u8('\\b');\n        const uint8x16_t s3 = vmovq_n_u8(32);\n\n        for (;; p += 16) {\n            const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));\n            uint8x16_t x = vceqq_u8(s, s0);\n            x = vorrq_u8(x, vceqq_u8(s, s1));\n            x = vorrq_u8(x, vceqq_u8(s, s2));\n            x = vorrq_u8(x, vcltq_u8(s, s3));\n\n            x = vrev64q_u8(x);                     // Rev in 64\n            uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract\n            uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract\n\n            if (low == 0) {\n                if (high != 0) {\n                    int lz = __builtin_clzll(high);\n                    p += 8 + (lz >> 3);\n                    break;\n                }\n            } else {\n                int lz = __builtin_clzll(low);\n                p += lz >> 3;\n                break;\n            }\n        }\n\n        is.src_ = is.dst_ = p;\n    }\n#endif // RAPIDJSON_NEON\n\n    template<typename InputStream, bool backup, bool pushOnTake>\n    class NumberStream;\n\n    template<typename InputStream>\n    class NumberStream<InputStream, false, false> {\n    public:\n        typedef typename InputStream::Ch Ch;\n\n        NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader;  }\n\n        RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }\n        RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }\n        RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }\n\t\t  RAPIDJSON_FORCEINLINE void Push(char) {}\n\n        size_t Tell() { return is.Tell(); }\n        size_t Length() { return 0; }\n        const char* Pop() { return 0; }\n\n    protected:\n        NumberStream& operator=(const NumberStream&);\n\n        InputStream& is;\n    };\n\n    template<typename InputStream>\n    class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {\n        typedef NumberStream<InputStream, false, false> Base;\n    public:\n        NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}\n\n        RAPIDJSON_FORCEINLINE Ch TakePush() {\n            stackStream.Put(static_cast<char>(Base::is.Peek()));\n            return Base::is.Take();\n        }\n\n        RAPIDJSON_FORCEINLINE void Push(char c) {\n            stackStream.Put(c);\n        }\n\n        size_t Length() { return stackStream.Length(); }\n\n        const char* Pop() {\n            stackStream.Put('\\0');\n            return stackStream.Pop();\n        }\n\n    private:\n        StackStream<char> stackStream;\n    };\n\n    template<typename InputStream>\n    class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {\n        typedef NumberStream<InputStream, true, false> Base;\n    public:\n        NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}\n\n        RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }\n    };\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseNumber(InputStream& is, Handler& handler) {\n        internal::StreamLocalCopy<InputStream> copy(is);\n        NumberStream<InputStream,\n            ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?\n                ((parseFlags & kParseInsituFlag) == 0) :\n                ((parseFlags & kParseFullPrecisionFlag) != 0),\n            (parseFlags & kParseNumbersAsStringsFlag) != 0 &&\n                (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);\n\n        size_t startOffset = s.Tell();\n        double d = 0.0;\n        bool useNanOrInf = false;\n\n        // Parse minus\n        bool minus = Consume(s, '-');\n\n        // Parse int: zero / ( digit1-9 *DIGIT )\n        unsigned i = 0;\n        uint64_t i64 = 0;\n        bool use64bit = false;\n        int significandDigit = 0;\n        if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {\n            i = 0;\n            s.TakePush();\n        }\n        else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {\n            i = static_cast<unsigned>(s.TakePush() - '0');\n\n            if (minus)\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648\n                        if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {\n                            i64 = i;\n                            use64bit = true;\n                            break;\n                        }\n                    }\n                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n            else\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295\n                        if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {\n                            i64 = i;\n                            use64bit = true;\n                            break;\n                        }\n                    }\n                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n        }\n        // Parse NaN or Infinity here\n        else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {\n            if (Consume(s, 'N')) {\n                if (Consume(s, 'a') && Consume(s, 'N')) {\n                    d = std::numeric_limits<double>::quiet_NaN();\n                    useNanOrInf = true;\n                }\n            }\n            else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) {\n                if (Consume(s, 'n') && Consume(s, 'f')) {\n                    d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());\n                    useNanOrInf = true;\n\n                    if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')\n                                                                && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) {\n                        RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n                    }\n                }\n            }\n\n            if (RAPIDJSON_UNLIKELY(!useNanOrInf)) {\n                RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n            }\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n\n        // Parse 64bit int\n        bool useDouble = false;\n        if (use64bit) {\n            if (minus)\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                     if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808\n                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {\n                            d = static_cast<double>(i64);\n                            useDouble = true;\n                            break;\n                        }\n                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n            else\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615\n                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {\n                            d = static_cast<double>(i64);\n                            useDouble = true;\n                            break;\n                        }\n                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n        }\n\n        // Force double for big integer\n        if (useDouble) {\n            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                d = d * 10 + (s.TakePush() - '0');\n            }\n        }\n\n        // Parse frac = decimal-point 1*DIGIT\n        int expFrac = 0;\n        size_t decimalPosition;\n        if (Consume(s, '.')) {\n            decimalPosition = s.Length();\n\n            if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))\n                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());\n\n            if (!useDouble) {\n#if RAPIDJSON_64BIT\n                // Use i64 to store significand in 64-bit architecture\n                if (!use64bit)\n                    i64 = i;\n\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path\n                        break;\n                    else {\n                        i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                        --expFrac;\n                        if (i64 != 0)\n                            significandDigit++;\n                    }\n                }\n\n                d = static_cast<double>(i64);\n#else\n                // Use double to store significand in 32-bit architecture\n                d = static_cast<double>(use64bit ? i64 : i);\n#endif\n                useDouble = true;\n            }\n\n            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                if (significandDigit < 17) {\n                    d = d * 10.0 + (s.TakePush() - '0');\n                    --expFrac;\n                    if (RAPIDJSON_LIKELY(d > 0.0))\n                        significandDigit++;\n                }\n                else\n                    s.TakePush();\n            }\n        }\n        else\n            decimalPosition = s.Length(); // decimal position at the end of integer.\n\n        // Parse exp = e [ minus / plus ] 1*DIGIT\n        int exp = 0;\n        if (Consume(s, 'e') || Consume(s, 'E')) {\n            if (!useDouble) {\n                d = static_cast<double>(use64bit ? i64 : i);\n                useDouble = true;\n            }\n\n            bool expMinus = false;\n            if (Consume(s, '+'))\n                ;\n            else if (Consume(s, '-'))\n                expMinus = true;\n\n            if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                exp = static_cast<int>(s.Take() - '0');\n                if (expMinus) {\n                    // (exp + expFrac) must not underflow int => we're detecting when -exp gets\n                    // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into\n                    // underflow territory):\n                    //\n                    //        -(exp * 10 + 9) + expFrac >= INT_MIN\n                    //   <=>  exp <= (expFrac - INT_MIN - 9) / 10\n                    RAPIDJSON_ASSERT(expFrac <= 0);\n                    int maxExp = (expFrac + 2147483639) / 10;\n\n                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                        exp = exp * 10 + static_cast<int>(s.Take() - '0');\n                        if (RAPIDJSON_UNLIKELY(exp > maxExp)) {\n                            while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9'))  // Consume the rest of exponent\n                                s.Take();\n                        }\n                    }\n                }\n                else {  // positive exp\n                    int maxExp = 308 - expFrac;\n                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                        exp = exp * 10 + static_cast<int>(s.Take() - '0');\n                        if (RAPIDJSON_UNLIKELY(exp > maxExp))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);\n                    }\n                }\n            }\n            else\n                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());\n\n            if (expMinus)\n                exp = -exp;\n        }\n\n        // Finish parsing, call event according to the type of number.\n        bool cont = true;\n\n        if (parseFlags & kParseNumbersAsStringsFlag) {\n            if (parseFlags & kParseInsituFlag) {\n                s.Pop();  // Pop stack no matter if it will be used or not.\n                typename InputStream::Ch* head = is.PutBegin();\n                const size_t length = s.Tell() - startOffset;\n                RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);\n                // unable to insert the \\0 character here, it will erase the comma after this number\n                const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);\n                cont = handler.RawNumber(str, SizeType(length), false);\n            }\n            else {\n                SizeType numCharsToCopy = static_cast<SizeType>(s.Length());\n                StringStream srcStream(s.Pop());\n                StackStream<typename TargetEncoding::Ch> dstStream(stack_);\n                while (numCharsToCopy--) {\n                    Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);\n                }\n                dstStream.Put('\\0');\n                const typename TargetEncoding::Ch* str = dstStream.Pop();\n                const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;\n                cont = handler.RawNumber(str, SizeType(length), true);\n            }\n        }\n        else {\n           size_t length = s.Length();\n           const char* decimal = s.Pop();  // Pop stack no matter if it will be used or not.\n\n           if (useDouble) {\n               int p = exp + expFrac;\n               if (parseFlags & kParseFullPrecisionFlag)\n                   d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);\n               else\n                   d = internal::StrtodNormalPrecision(d, p);\n\n               // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal\n               if (d > (std::numeric_limits<double>::max)()) {\n                   // Overflow\n                   // TODO: internal::StrtodX should report overflow (or underflow)\n                   RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);\n               }\n\n               cont = handler.Double(minus ? -d : d);\n           }\n           else if (useNanOrInf) {\n               cont = handler.Double(d);\n           }\n           else {\n               if (use64bit) {\n                   if (minus)\n                       cont = handler.Int64(static_cast<int64_t>(~i64 + 1));\n                   else\n                       cont = handler.Uint64(i64);\n               }\n               else {\n                   if (minus)\n                       cont = handler.Int(static_cast<int32_t>(~i + 1));\n                   else\n                       cont = handler.Uint(i);\n               }\n           }\n        }\n        if (RAPIDJSON_UNLIKELY(!cont))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);\n    }\n\n    // Parse any JSON value\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseValue(InputStream& is, Handler& handler) {\n        switch (is.Peek()) {\n            case 'n': ParseNull  <parseFlags>(is, handler); break;\n            case 't': ParseTrue  <parseFlags>(is, handler); break;\n            case 'f': ParseFalse <parseFlags>(is, handler); break;\n            case '\"': ParseString<parseFlags>(is, handler); break;\n            case '{': ParseObject<parseFlags>(is, handler); break;\n            case '[': ParseArray <parseFlags>(is, handler); break;\n            default :\n                      ParseNumber<parseFlags>(is, handler);\n                      break;\n\n        }\n    }\n\n    // Iterative Parsing\n\n    // States\n    enum IterativeParsingState {\n        IterativeParsingFinishState = 0, // sink states at top\n        IterativeParsingErrorState,      // sink states at top\n        IterativeParsingStartState,\n\n        // Object states\n        IterativeParsingObjectInitialState,\n        IterativeParsingMemberKeyState,\n        IterativeParsingMemberValueState,\n        IterativeParsingObjectFinishState,\n\n        // Array states\n        IterativeParsingArrayInitialState,\n        IterativeParsingElementState,\n        IterativeParsingArrayFinishState,\n\n        // Single value state\n        IterativeParsingValueState,\n\n        // Delimiter states (at bottom)\n        IterativeParsingElementDelimiterState,\n        IterativeParsingMemberDelimiterState,\n        IterativeParsingKeyValueDelimiterState,\n\n        cIterativeParsingStateCount\n    };\n\n    // Tokens\n    enum Token {\n        LeftBracketToken = 0,\n        RightBracketToken,\n\n        LeftCurlyBracketToken,\n        RightCurlyBracketToken,\n\n        CommaToken,\n        ColonToken,\n\n        StringToken,\n        FalseToken,\n        TrueToken,\n        NullToken,\n        NumberToken,\n\n        kTokenCount\n    };\n\n    RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const {\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define N NumberToken\n#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N\n        // Maps from ASCII to Token\n        static const unsigned char tokenMap[256] = {\n            N16, // 00~0F\n            N16, // 10~1F\n            N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F\n            N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F\n            N16, // 40~4F\n            N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F\n            N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F\n            N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F\n            N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF\n        };\n#undef N\n#undef N16\n//!@endcond\n\n        if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)\n            return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);\n        else\n            return NumberToken;\n    }\n\n    RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const {\n        // current state x one lookahead token -> new state\n        static const char G[cIterativeParsingStateCount][kTokenCount] = {\n            // Finish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Error(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Start\n            {\n                IterativeParsingArrayInitialState,  // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingObjectInitialState, // Left curly bracket\n                IterativeParsingErrorState,         // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingValueState,         // String\n                IterativeParsingValueState,         // False\n                IterativeParsingValueState,         // True\n                IterativeParsingValueState,         // Null\n                IterativeParsingValueState          // Number\n            },\n            // ObjectInitial\n            {\n                IterativeParsingErrorState,         // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingErrorState,         // Left curly bracket\n                IterativeParsingObjectFinishState,  // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingMemberKeyState,     // String\n                IterativeParsingErrorState,         // False\n                IterativeParsingErrorState,         // True\n                IterativeParsingErrorState,         // Null\n                IterativeParsingErrorState          // Number\n            },\n            // MemberKey\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingKeyValueDelimiterState, // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // MemberValue\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingObjectFinishState,      // Right curly bracket\n                IterativeParsingMemberDelimiterState,   // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // ObjectFinish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // ArrayInitial\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push Element state)\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingElementState,           // String\n                IterativeParsingElementState,           // False\n                IterativeParsingElementState,           // True\n                IterativeParsingElementState,           // Null\n                IterativeParsingElementState            // Number\n            },\n            // Element\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingElementDelimiterState,  // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // ArrayFinish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Single Value (sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // ElementDelimiter\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push Element state)\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingElementState,           // String\n                IterativeParsingElementState,           // False\n                IterativeParsingElementState,           // True\n                IterativeParsingElementState,           // Null\n                IterativeParsingElementState            // Number\n            },\n            // MemberDelimiter\n            {\n                IterativeParsingErrorState,         // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingErrorState,         // Left curly bracket\n                IterativeParsingObjectFinishState,  // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingMemberKeyState,     // String\n                IterativeParsingErrorState,         // False\n                IterativeParsingErrorState,         // True\n                IterativeParsingErrorState,         // Null\n                IterativeParsingErrorState          // Number\n            },\n            // KeyValueDelimiter\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push MemberValue state)\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push MemberValue state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingMemberValueState,       // String\n                IterativeParsingMemberValueState,       // False\n                IterativeParsingMemberValueState,       // True\n                IterativeParsingMemberValueState,       // Null\n                IterativeParsingMemberValueState        // Number\n            },\n        }; // End of G\n\n        return static_cast<IterativeParsingState>(G[state][token]);\n    }\n\n    // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().\n    // May return a new state on state pop.\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {\n        (void)token;\n\n        switch (dst) {\n        case IterativeParsingErrorState:\n            return dst;\n\n        case IterativeParsingObjectInitialState:\n        case IterativeParsingArrayInitialState:\n        {\n            // Push the state(Element or MemeberValue) if we are nested in another array or value of member.\n            // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.\n            IterativeParsingState n = src;\n            if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)\n                n = IterativeParsingElementState;\n            else if (src == IterativeParsingKeyValueDelimiterState)\n                n = IterativeParsingMemberValueState;\n            // Push current state.\n            *stack_.template Push<SizeType>(1) = n;\n            // Initialize and push the member/element count.\n            *stack_.template Push<SizeType>(1) = 0;\n            // Call handler\n            bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return dst;\n            }\n        }\n\n        case IterativeParsingMemberKeyState:\n            ParseString<parseFlags>(is, handler, true);\n            if (HasParseError())\n                return IterativeParsingErrorState;\n            else\n                return dst;\n\n        case IterativeParsingKeyValueDelimiterState:\n            RAPIDJSON_ASSERT(token == ColonToken);\n            is.Take();\n            return dst;\n\n        case IterativeParsingMemberValueState:\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return dst;\n\n        case IterativeParsingElementState:\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return dst;\n\n        case IterativeParsingMemberDelimiterState:\n        case IterativeParsingElementDelimiterState:\n            is.Take();\n            // Update member/element count.\n            *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;\n            return dst;\n\n        case IterativeParsingObjectFinishState:\n        {\n            // Transit from delimiter is only allowed when trailing commas are enabled\n            if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            // Get member count.\n            SizeType c = *stack_.template Pop<SizeType>(1);\n            // If the object is not empty, count the last member.\n            if (src == IterativeParsingMemberValueState)\n                ++c;\n            // Restore the state.\n            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));\n            // Transit to Finish state if this is the topmost scope.\n            if (n == IterativeParsingStartState)\n                n = IterativeParsingFinishState;\n            // Call handler\n            bool hr = handler.EndObject(c);\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return n;\n            }\n        }\n\n        case IterativeParsingArrayFinishState:\n        {\n            // Transit from delimiter is only allowed when trailing commas are enabled\n            if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            // Get element count.\n            SizeType c = *stack_.template Pop<SizeType>(1);\n            // If the array is not empty, count the last element.\n            if (src == IterativeParsingElementState)\n                ++c;\n            // Restore the state.\n            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));\n            // Transit to Finish state if this is the topmost scope.\n            if (n == IterativeParsingStartState)\n                n = IterativeParsingFinishState;\n            // Call handler\n            bool hr = handler.EndArray(c);\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return n;\n            }\n        }\n\n        default:\n            // This branch is for IterativeParsingValueState actually.\n            // Use `default:` rather than\n            // `case IterativeParsingValueState:` is for code coverage.\n\n            // The IterativeParsingStartState is not enumerated in this switch-case.\n            // It is impossible for that case. And it can be caught by following assertion.\n\n            // The IterativeParsingFinishState is not enumerated in this switch-case either.\n            // It is a \"derivative\" state which cannot triggered from Predict() directly.\n            // Therefore it cannot happen here. And it can be caught by following assertion.\n            RAPIDJSON_ASSERT(dst == IterativeParsingValueState);\n\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return IterativeParsingFinishState;\n        }\n    }\n\n    template <typename InputStream>\n    void HandleError(IterativeParsingState src, InputStream& is) {\n        if (HasParseError()) {\n            // Error flag has been set.\n            return;\n        }\n\n        switch (src) {\n        case IterativeParsingStartState:            RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;\n        case IterativeParsingFinishState:           RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;\n        case IterativeParsingObjectInitialState:\n        case IterativeParsingMemberDelimiterState:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;\n        case IterativeParsingMemberKeyState:        RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;\n        case IterativeParsingMemberValueState:      RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;\n        case IterativeParsingKeyValueDelimiterState:\n        case IterativeParsingArrayInitialState:\n        case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;\n        default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;\n        }\n    }\n\n    RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const {\n        return s >= IterativeParsingElementDelimiterState;\n    }\n\n    RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const {\n        return s <= IterativeParsingErrorState;\n    }\n\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    ParseResult IterativeParse(InputStream& is, Handler& handler) {\n        parseResult_.Clear();\n        ClearStackOnExit scope(*this);\n        IterativeParsingState state = IterativeParsingStartState;\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        while (is.Peek() != '\\0') {\n            Token t = Tokenize(is.Peek());\n            IterativeParsingState n = Predict(state, t);\n            IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);\n\n            if (d == IterativeParsingErrorState) {\n                HandleError(state, is);\n                break;\n            }\n\n            state = d;\n\n            // Do not further consume streams if a root JSON has been parsed.\n            if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)\n                break;\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        }\n\n        // Handle the end of file.\n        if (state != IterativeParsingFinishState)\n            HandleError(state, is);\n\n        return parseResult_;\n    }\n\n    static const size_t kDefaultStackCapacity = 256;    //!< Default stack capacity in bytes for storing a single decoded string.\n    internal::Stack<StackAllocator> stack_;  //!< A stack for storing decoded string temporarily during non-destructive parsing.\n    ParseResult parseResult_;\n    IterativeParsingState state_;\n}; // class GenericReader\n\n//! Reader with UTF8 encoding and default allocator.\ntypedef GenericReader<UTF8<>, UTF8<> > Reader;\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_READER_H_\n"
  },
  {
    "path": "src/json/rapidjson/schema.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available->\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License-> You may obtain a copy of the License at\n//\n// http://opensource->org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied-> See the License for the \n// specific language governing permissions and limitations under the License->\n\n#ifndef RAPIDJSON_SCHEMA_H_\n#define RAPIDJSON_SCHEMA_H_\n\n#include \"document.h\"\n#include \"pointer.h\"\n#include \"stringbuffer.h\"\n#include <cmath> // abs, floor\n\n#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)\n#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1\n#else\n#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0\n#endif\n\n#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))\n#define RAPIDJSON_SCHEMA_USE_STDREGEX 1\n#else\n#define RAPIDJSON_SCHEMA_USE_STDREGEX 0\n#endif\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX\n#include \"src/json/rapidjson/internal/regex.h\"\n#elif RAPIDJSON_SCHEMA_USE_STDREGEX\n#include <regex>\n#endif\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX\n#define RAPIDJSON_SCHEMA_HAS_REGEX 1\n#else\n#define RAPIDJSON_SCHEMA_HAS_REGEX 0\n#endif\n\n#ifndef RAPIDJSON_SCHEMA_VERBOSE\n#define RAPIDJSON_SCHEMA_VERBOSE 0\n#endif\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n#include \"stringbuffer.h\"\n#endif\n\nRAPIDJSON_DIAG_PUSH\n\n#if defined(__GNUC__)\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_OFF(weak-vtables)\nRAPIDJSON_DIAG_OFF(exit-time-destructors)\nRAPIDJSON_DIAG_OFF(c++98-compat-pedantic)\nRAPIDJSON_DIAG_OFF(variadic-macros)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Verbose Utilities\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n\nnamespace internal {\n\ninline void PrintInvalidKeyword(const char* keyword) {\n    printf(\"Fail keyword: %s\\n\", keyword);\n}\n\ninline void PrintInvalidKeyword(const wchar_t* keyword) {\n    wprintf(L\"Fail keyword: %ls\\n\", keyword);\n}\n\ninline void PrintInvalidDocument(const char* document) {\n    printf(\"Fail document: %s\\n\\n\", document);\n}\n\ninline void PrintInvalidDocument(const wchar_t* document) {\n    wprintf(L\"Fail document: %ls\\n\\n\", document);\n}\n\ninline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {\n    printf(\"S: %*s%s\\nD: %*s%s\\n\\n\", depth * 4, \" \", s, depth * 4, \" \", d);\n}\n\ninline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {\n    wprintf(L\"S: %*ls%ls\\nD: %*ls%ls\\n\\n\", depth * 4, L\" \", s, depth * 4, L\" \", d);\n}\n\n} // namespace internal\n\n#endif // RAPIDJSON_SCHEMA_VERBOSE\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_INVALID_KEYWORD_RETURN\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)\n#else\n#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)\n#endif\n\n#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\\\nRAPIDJSON_MULTILINEMACRO_BEGIN\\\n    context.invalidKeyword = keyword.GetString();\\\n    RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\\\n    return false;\\\nRAPIDJSON_MULTILINEMACRO_END\n\n///////////////////////////////////////////////////////////////////////////////\n// Forward declarations\n\ntemplate <typename ValueType, typename Allocator>\nclass GenericSchemaDocument;\n\nnamespace internal {\n\ntemplate <typename SchemaDocumentType>\nclass Schema;\n\n///////////////////////////////////////////////////////////////////////////////\n// ISchemaValidator\n\nclass ISchemaValidator {\npublic:\n    virtual ~ISchemaValidator() {}\n    virtual bool IsValid() const = 0;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// ISchemaStateFactory\n\ntemplate <typename SchemaType>\nclass ISchemaStateFactory {\npublic:\n    virtual ~ISchemaStateFactory() {}\n    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;\n    virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;\n    virtual void* CreateHasher() = 0;\n    virtual uint64_t GetHashCode(void* hasher) = 0;\n    virtual void DestroryHasher(void* hasher) = 0;\n    virtual void* MallocState(size_t size) = 0;\n    virtual void FreeState(void* p) = 0;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// IValidationErrorHandler\n\ntemplate <typename SchemaType>\nclass IValidationErrorHandler {\npublic:\n    typedef typename SchemaType::Ch Ch;\n    typedef typename SchemaType::SValue SValue;\n\n    virtual ~IValidationErrorHandler() {}\n\n    virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;\n    virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;\n    virtual void NotMultipleOf(double actual, const SValue& expected) = 0;\n    virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;\n    virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;\n    virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;\n    virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;\n    virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;\n    virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;\n\n    virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;\n    virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;\n    virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;\n\n    virtual void DisallowedItem(SizeType index) = 0;\n    virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;\n    virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;\n    virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;\n\n    virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;\n    virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;\n    virtual void StartMissingProperties() = 0;\n    virtual void AddMissingProperty(const SValue& name) = 0;\n    virtual bool EndMissingProperties() = 0;\n    virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;\n    virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;\n\n    virtual void StartDependencyErrors() = 0;\n    virtual void StartMissingDependentProperties() = 0;\n    virtual void AddMissingDependentProperty(const SValue& targetName) = 0;\n    virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;\n    virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;\n    virtual bool EndDependencyErrors() = 0;\n\n    virtual void DisallowedValue() = 0;\n    virtual void StartDisallowedType() = 0;\n    virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;\n    virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;\n    virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;\n    virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;\n    virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;\n    virtual void Disallowed() = 0;\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Hasher\n\n// For comparison of compound value\ntemplate<typename Encoding, typename Allocator>\nclass Hasher {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}\n\n    bool Null() { return WriteType(kNullType); }\n    bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }\n    bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }\n    bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }\n    bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }\n    bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }\n    bool Double(double d) { \n        Number n; \n        if (d < 0) n.u.i = static_cast<int64_t>(d);\n        else       n.u.u = static_cast<uint64_t>(d); \n        n.d = d;\n        return WriteNumber(n);\n    }\n\n    bool RawNumber(const Ch* str, SizeType len, bool) {\n        WriteBuffer(kNumberType, str, len * sizeof(Ch));\n        return true;\n    }\n\n    bool String(const Ch* str, SizeType len, bool) {\n        WriteBuffer(kStringType, str, len * sizeof(Ch));\n        return true;\n    }\n\n    bool StartObject() { return true; }\n    bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }\n    bool EndObject(SizeType memberCount) { \n        uint64_t h = Hash(0, kObjectType);\n        uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);\n        for (SizeType i = 0; i < memberCount; i++)\n            h ^= Hash(kv[i * 2], kv[i * 2 + 1]);  // Use xor to achieve member order insensitive\n        *stack_.template Push<uint64_t>() = h;\n        return true;\n    }\n    \n    bool StartArray() { return true; }\n    bool EndArray(SizeType elementCount) { \n        uint64_t h = Hash(0, kArrayType);\n        uint64_t* e = stack_.template Pop<uint64_t>(elementCount);\n        for (SizeType i = 0; i < elementCount; i++)\n            h = Hash(h, e[i]); // Use hash to achieve element order sensitive\n        *stack_.template Push<uint64_t>() = h;\n        return true;\n    }\n\n    bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }\n\n    uint64_t GetHashCode() const {\n        RAPIDJSON_ASSERT(IsValid());\n        return *stack_.template Top<uint64_t>();\n    }\n\nprivate:\n    static const size_t kDefaultSize = 256;\n    struct Number {\n        union U {\n            uint64_t u;\n            int64_t i;\n        }u;\n        double d;\n    };\n\n    bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }\n    \n    bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }\n    \n    bool WriteBuffer(Type type, const void* data, size_t len) {\n        // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/\n        uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);\n        const unsigned char* d = static_cast<const unsigned char*>(data);\n        for (size_t i = 0; i < len; i++)\n            h = Hash(h, d[i]);\n        *stack_.template Push<uint64_t>() = h;\n        return true;\n    }\n\n    static uint64_t Hash(uint64_t h, uint64_t d) {\n        static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);\n        h ^= d;\n        h *= kPrime;\n        return h;\n    }\n\n    Stack<Allocator> stack_;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// SchemaValidationContext\n\ntemplate <typename SchemaDocumentType>\nstruct SchemaValidationContext {\n    typedef Schema<SchemaDocumentType> SchemaType;\n    typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;\n    typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;\n    typedef typename SchemaType::ValueType ValueType;\n    typedef typename ValueType::Ch Ch;\n\n    enum PatternValidatorType {\n        kPatternValidatorOnly,\n        kPatternValidatorWithProperty,\n        kPatternValidatorWithAdditionalProperty\n    };\n\n    SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) :\n        factory(f),\n        error_handler(eh),\n        schema(s),\n        valueSchema(),\n        invalidKeyword(),\n        hasher(),\n        arrayElementHashCodes(),\n        validators(),\n        validatorCount(),\n        patternPropertiesValidators(),\n        patternPropertiesValidatorCount(),\n        patternPropertiesSchemas(),\n        patternPropertiesSchemaCount(),\n        valuePatternValidatorType(kPatternValidatorOnly),\n        propertyExist(),\n        inArray(false),\n        valueUniqueness(false),\n        arrayUniqueness(false)\n    {\n    }\n\n    ~SchemaValidationContext() {\n        if (hasher)\n            factory.DestroryHasher(hasher);\n        if (validators) {\n            for (SizeType i = 0; i < validatorCount; i++)\n                factory.DestroySchemaValidator(validators[i]);\n            factory.FreeState(validators);\n        }\n        if (patternPropertiesValidators) {\n            for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)\n                factory.DestroySchemaValidator(patternPropertiesValidators[i]);\n            factory.FreeState(patternPropertiesValidators);\n        }\n        if (patternPropertiesSchemas)\n            factory.FreeState(patternPropertiesSchemas);\n        if (propertyExist)\n            factory.FreeState(propertyExist);\n    }\n\n    SchemaValidatorFactoryType& factory;\n    ErrorHandlerType& error_handler;\n    const SchemaType* schema;\n    const SchemaType* valueSchema;\n    const Ch* invalidKeyword;\n    void* hasher; // Only validator access\n    void* arrayElementHashCodes; // Only validator access this\n    ISchemaValidator** validators;\n    SizeType validatorCount;\n    ISchemaValidator** patternPropertiesValidators;\n    SizeType patternPropertiesValidatorCount;\n    const SchemaType** patternPropertiesSchemas;\n    SizeType patternPropertiesSchemaCount;\n    PatternValidatorType valuePatternValidatorType;\n    PatternValidatorType objectPatternValidatorType;\n    SizeType arrayElementIndex;\n    bool* propertyExist;\n    bool inArray;\n    bool valueUniqueness;\n    bool arrayUniqueness;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Schema\n\ntemplate <typename SchemaDocumentType>\nclass Schema {\npublic:\n    typedef typename SchemaDocumentType::ValueType ValueType;\n    typedef typename SchemaDocumentType::AllocatorType AllocatorType;\n    typedef typename SchemaDocumentType::PointerType PointerType;\n    typedef typename ValueType::EncodingType EncodingType;\n    typedef typename EncodingType::Ch Ch;\n    typedef SchemaValidationContext<SchemaDocumentType> Context;\n    typedef Schema<SchemaDocumentType> SchemaType;\n    typedef GenericValue<EncodingType, AllocatorType> SValue;\n    typedef IValidationErrorHandler<Schema> ErrorHandler;\n    friend class GenericSchemaDocument<ValueType, AllocatorType>;\n\n    Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :\n        allocator_(allocator),\n        uri_(schemaDocument->GetURI(), *allocator),\n        pointer_(p, allocator),\n        typeless_(schemaDocument->GetTypeless()),\n        enum_(),\n        enumCount_(),\n        not_(),\n        type_((1 << kTotalSchemaType) - 1), // typeless\n        validatorCount_(),\n        notValidatorIndex_(),\n        properties_(),\n        additionalPropertiesSchema_(),\n        patternProperties_(),\n        patternPropertyCount_(),\n        propertyCount_(),\n        minProperties_(),\n        maxProperties_(SizeType(~0)),\n        additionalProperties_(true),\n        hasDependencies_(),\n        hasRequired_(),\n        hasSchemaDependencies_(),\n        additionalItemsSchema_(),\n        itemsList_(),\n        itemsTuple_(),\n        itemsTupleCount_(),\n        minItems_(),\n        maxItems_(SizeType(~0)),\n        additionalItems_(true),\n        uniqueItems_(false),\n        pattern_(),\n        minLength_(0),\n        maxLength_(~SizeType(0)),\n        exclusiveMinimum_(false),\n        exclusiveMaximum_(false),\n        defaultValueLength_(0)\n    {\n        typedef typename SchemaDocumentType::ValueType ValueType;\n        typedef typename ValueType::ConstValueIterator ConstValueIterator;\n        typedef typename ValueType::ConstMemberIterator ConstMemberIterator;\n\n        if (!value.IsObject())\n            return;\n\n        if (const ValueType* v = GetMember(value, GetTypeString())) {\n            type_ = 0;\n            if (v->IsString())\n                AddType(*v);\n            else if (v->IsArray())\n                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)\n                    AddType(*itr);\n        }\n\n        if (const ValueType* v = GetMember(value, GetEnumString()))\n            if (v->IsArray() && v->Size() > 0) {\n                enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));\n                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {\n                    typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;\n                    char buffer[256u + 24];\n                    MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));\n                    EnumHasherType h(&hasherAllocator, 256);\n                    itr->Accept(h);\n                    enum_[enumCount_++] = h.GetHashCode();\n                }\n            }\n\n        if (schemaDocument) {\n            AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);\n            AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);\n            AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);\n        }\n\n        if (const ValueType* v = GetMember(value, GetNotString())) {\n            schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);\n            notValidatorIndex_ = validatorCount_;\n            validatorCount_++;\n        }\n\n        // Object\n\n        const ValueType* properties = GetMember(value, GetPropertiesString());\n        const ValueType* required = GetMember(value, GetRequiredString());\n        const ValueType* dependencies = GetMember(value, GetDependenciesString());\n        {\n            // Gather properties from properties/required/dependencies\n            SValue allProperties(kArrayType);\n\n            if (properties && properties->IsObject())\n                for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)\n                    AddUniqueElement(allProperties, itr->name);\n            \n            if (required && required->IsArray())\n                for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)\n                    if (itr->IsString())\n                        AddUniqueElement(allProperties, *itr);\n\n            if (dependencies && dependencies->IsObject())\n                for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {\n                    AddUniqueElement(allProperties, itr->name);\n                    if (itr->value.IsArray())\n                        for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)\n                            if (i->IsString())\n                                AddUniqueElement(allProperties, *i);\n                }\n\n            if (allProperties.Size() > 0) {\n                propertyCount_ = allProperties.Size();\n                properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));\n                for (SizeType i = 0; i < propertyCount_; i++) {\n                    new (&properties_[i]) Property();\n                    properties_[i].name = allProperties[i];\n                    properties_[i].schema = typeless_;\n                }\n            }\n        }\n\n        if (properties && properties->IsObject()) {\n            PointerType q = p.Append(GetPropertiesString(), allocator_);\n            for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {\n                SizeType index;\n                if (FindPropertyIndex(itr->name, &index))\n                    schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);\n            }\n        }\n\n        if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {\n            PointerType q = p.Append(GetPatternPropertiesString(), allocator_);\n            patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));\n            patternPropertyCount_ = 0;\n\n            for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {\n                new (&patternProperties_[patternPropertyCount_]) PatternProperty();\n                patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);\n                schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);\n                patternPropertyCount_++;\n            }\n        }\n\n        if (required && required->IsArray())\n            for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)\n                if (itr->IsString()) {\n                    SizeType index;\n                    if (FindPropertyIndex(*itr, &index)) {\n                        properties_[index].required = true;\n                        hasRequired_ = true;\n                    }\n                }\n\n        if (dependencies && dependencies->IsObject()) {\n            PointerType q = p.Append(GetDependenciesString(), allocator_);\n            hasDependencies_ = true;\n            for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {\n                SizeType sourceIndex;\n                if (FindPropertyIndex(itr->name, &sourceIndex)) {\n                    if (itr->value.IsArray()) {\n                        properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));\n                        std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);\n                        for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {\n                            SizeType targetIndex;\n                            if (FindPropertyIndex(*targetItr, &targetIndex))\n                                properties_[sourceIndex].dependencies[targetIndex] = true;\n                        }\n                    }\n                    else if (itr->value.IsObject()) {\n                        hasSchemaDependencies_ = true;\n                        schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);\n                        properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;\n                        validatorCount_++;\n                    }\n                }\n            }\n        }\n\n        if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {\n            if (v->IsBool())\n                additionalProperties_ = v->GetBool();\n            else if (v->IsObject())\n                schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);\n        }\n\n        AssignIfExist(minProperties_, value, GetMinPropertiesString());\n        AssignIfExist(maxProperties_, value, GetMaxPropertiesString());\n\n        // Array\n        if (const ValueType* v = GetMember(value, GetItemsString())) {\n            PointerType q = p.Append(GetItemsString(), allocator_);\n            if (v->IsObject()) // List validation\n                schemaDocument->CreateSchema(&itemsList_, q, *v, document);\n            else if (v->IsArray()) { // Tuple validation\n                itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));\n                SizeType index = 0;\n                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)\n                    schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);\n            }\n        }\n\n        AssignIfExist(minItems_, value, GetMinItemsString());\n        AssignIfExist(maxItems_, value, GetMaxItemsString());\n\n        if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {\n            if (v->IsBool())\n                additionalItems_ = v->GetBool();\n            else if (v->IsObject())\n                schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);\n        }\n\n        AssignIfExist(uniqueItems_, value, GetUniqueItemsString());\n\n        // String\n        AssignIfExist(minLength_, value, GetMinLengthString());\n        AssignIfExist(maxLength_, value, GetMaxLengthString());\n\n        if (const ValueType* v = GetMember(value, GetPatternString()))\n            pattern_ = CreatePattern(*v);\n\n        // Number\n        if (const ValueType* v = GetMember(value, GetMinimumString()))\n            if (v->IsNumber())\n                minimum_.CopyFrom(*v, *allocator_);\n\n        if (const ValueType* v = GetMember(value, GetMaximumString()))\n            if (v->IsNumber())\n                maximum_.CopyFrom(*v, *allocator_);\n\n        AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());\n        AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());\n\n        if (const ValueType* v = GetMember(value, GetMultipleOfString()))\n            if (v->IsNumber() && v->GetDouble() > 0.0)\n                multipleOf_.CopyFrom(*v, *allocator_);\n\n        // Default\n        if (const ValueType* v = GetMember(value, GetDefaultValueString()))\n            if (v->IsString())\n                defaultValueLength_ = v->GetStringLength();\n\n    }\n\n    ~Schema() {\n        AllocatorType::Free(enum_);\n        if (properties_) {\n            for (SizeType i = 0; i < propertyCount_; i++)\n                properties_[i].~Property();\n            AllocatorType::Free(properties_);\n        }\n        if (patternProperties_) {\n            for (SizeType i = 0; i < patternPropertyCount_; i++)\n                patternProperties_[i].~PatternProperty();\n            AllocatorType::Free(patternProperties_);\n        }\n        AllocatorType::Free(itemsTuple_);\n#if RAPIDJSON_SCHEMA_HAS_REGEX\n        if (pattern_) {\n            pattern_->~RegexType();\n            AllocatorType::Free(pattern_);\n        }\n#endif\n    }\n\n    const SValue& GetURI() const {\n        return uri_;\n    }\n\n    const PointerType& GetPointer() const {\n        return pointer_;\n    }\n\n    bool BeginValue(Context& context) const {\n        if (context.inArray) {\n            if (uniqueItems_)\n                context.valueUniqueness = true;\n\n            if (itemsList_)\n                context.valueSchema = itemsList_;\n            else if (itemsTuple_) {\n                if (context.arrayElementIndex < itemsTupleCount_)\n                    context.valueSchema = itemsTuple_[context.arrayElementIndex];\n                else if (additionalItemsSchema_)\n                    context.valueSchema = additionalItemsSchema_;\n                else if (additionalItems_)\n                    context.valueSchema = typeless_;\n                else {\n                    context.error_handler.DisallowedItem(context.arrayElementIndex);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());\n                }\n            }\n            else\n                context.valueSchema = typeless_;\n\n            context.arrayElementIndex++;\n        }\n        return true;\n    }\n\n    RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {\n        if (context.patternPropertiesValidatorCount > 0) {\n            bool otherValid = false;\n            SizeType count = context.patternPropertiesValidatorCount;\n            if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)\n                otherValid = context.patternPropertiesValidators[--count]->IsValid();\n\n            bool patternValid = true;\n            for (SizeType i = 0; i < count; i++)\n                if (!context.patternPropertiesValidators[i]->IsValid()) {\n                    patternValid = false;\n                    break;\n                }\n\n            if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {\n                if (!patternValid) {\n                    context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());\n                }\n            }\n            else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {\n                if (!patternValid || !otherValid) {\n                    context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());\n                }\n            }\n            else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)\n                context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());\n            }\n        }\n\n        if (enum_) {\n            const uint64_t h = context.factory.GetHashCode(context.hasher);\n            for (SizeType i = 0; i < enumCount_; i++)\n                if (enum_[i] == h)\n                    goto foundEnum;\n            context.error_handler.DisallowedValue();\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());\n            foundEnum:;\n        }\n\n        if (allOf_.schemas)\n            for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)\n                if (!context.validators[i]->IsValid()) {\n                    context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());\n                }\n        \n        if (anyOf_.schemas) {\n            for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)\n                if (context.validators[i]->IsValid())\n                    goto foundAny;\n            context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());\n            foundAny:;\n        }\n\n        if (oneOf_.schemas) {\n            bool oneValid = false;\n            for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)\n                if (context.validators[i]->IsValid()) {\n                    if (oneValid) {\n                        context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);\n                        RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());\n                    } else\n                        oneValid = true;\n                }\n            if (!oneValid) {\n                context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());\n            }\n        }\n\n        if (not_ && context.validators[notValidatorIndex_]->IsValid()) {\n            context.error_handler.Disallowed();\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());\n        }\n\n        return true;\n    }\n\n    bool Null(Context& context) const {\n        if (!(type_ & (1 << kNullSchemaType))) {\n            DisallowedType(context, GetNullString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n        return CreateParallelValidator(context);\n    }\n    \n    bool Bool(Context& context, bool) const {\n        if (!(type_ & (1 << kBooleanSchemaType))) {\n            DisallowedType(context, GetBooleanString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n        return CreateParallelValidator(context);\n    }\n\n    bool Int(Context& context, int i) const {\n        if (!CheckInt(context, i))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Uint(Context& context, unsigned u) const {\n        if (!CheckUint(context, u))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Int64(Context& context, int64_t i) const {\n        if (!CheckInt(context, i))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Uint64(Context& context, uint64_t u) const {\n        if (!CheckUint(context, u))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Double(Context& context, double d) const {\n        if (!(type_ & (1 << kNumberSchemaType))) {\n            DisallowedType(context, GetNumberString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n\n        if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))\n            return false;\n\n        if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))\n            return false;\n        \n        if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))\n            return false;\n        \n        return CreateParallelValidator(context);\n    }\n    \n    bool String(Context& context, const Ch* str, SizeType length, bool) const {\n        if (!(type_ & (1 << kStringSchemaType))) {\n            DisallowedType(context, GetStringString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n\n        if (minLength_ != 0 || maxLength_ != SizeType(~0)) {\n            SizeType count;\n            if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {\n                if (count < minLength_) {\n                    context.error_handler.TooShort(str, length, minLength_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());\n                }\n                if (count > maxLength_) {\n                    context.error_handler.TooLong(str, length, maxLength_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());\n                }\n            }\n        }\n\n        if (pattern_ && !IsPatternMatch(pattern_, str, length)) {\n            context.error_handler.DoesNotMatch(str, length);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());\n        }\n\n        return CreateParallelValidator(context);\n    }\n\n    bool StartObject(Context& context) const {\n        if (!(type_ & (1 << kObjectSchemaType))) {\n            DisallowedType(context, GetObjectString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n\n        if (hasDependencies_ || hasRequired_) {\n            context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));\n            std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);\n        }\n\n        if (patternProperties_) { // pre-allocate schema array\n            SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType\n            context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));\n            context.patternPropertiesSchemaCount = 0;\n            std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);\n        }\n\n        return CreateParallelValidator(context);\n    }\n    \n    bool Key(Context& context, const Ch* str, SizeType len, bool) const {\n        if (patternProperties_) {\n            context.patternPropertiesSchemaCount = 0;\n            for (SizeType i = 0; i < patternPropertyCount_; i++)\n                if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {\n                    context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;\n                    context.valueSchema = typeless_;\n                }\n        }\n\n        SizeType index;\n        if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {\n            if (context.patternPropertiesSchemaCount > 0) {\n                context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;\n                context.valueSchema = typeless_;\n                context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;\n            }\n            else\n                context.valueSchema = properties_[index].schema;\n\n            if (context.propertyExist)\n                context.propertyExist[index] = true;\n\n            return true;\n        }\n\n        if (additionalPropertiesSchema_) {\n            if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {\n                context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;\n                context.valueSchema = typeless_;\n                context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;\n            }\n            else\n                context.valueSchema = additionalPropertiesSchema_;\n            return true;\n        }\n        else if (additionalProperties_) {\n            context.valueSchema = typeless_;\n            return true;\n        }\n\n        if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties\n            context.error_handler.DisallowedProperty(str, len);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());\n        }\n\n        return true;\n    }\n\n    bool EndObject(Context& context, SizeType memberCount) const {\n        if (hasRequired_) {\n            context.error_handler.StartMissingProperties();\n            for (SizeType index = 0; index < propertyCount_; index++)\n                if (properties_[index].required && !context.propertyExist[index])\n                    if (properties_[index].schema->defaultValueLength_ == 0 )\n                        context.error_handler.AddMissingProperty(properties_[index].name);\n            if (context.error_handler.EndMissingProperties())\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());\n        }\n\n        if (memberCount < minProperties_) {\n            context.error_handler.TooFewProperties(memberCount, minProperties_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());\n        }\n\n        if (memberCount > maxProperties_) {\n            context.error_handler.TooManyProperties(memberCount, maxProperties_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());\n        }\n\n        if (hasDependencies_) {\n            context.error_handler.StartDependencyErrors();\n            for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {\n                const Property& source = properties_[sourceIndex];\n                if (context.propertyExist[sourceIndex]) {\n                    if (source.dependencies) {\n                        context.error_handler.StartMissingDependentProperties();\n                        for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)\n                            if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])\n                                context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);\n                        context.error_handler.EndMissingDependentProperties(source.name);\n                    }\n                    else if (source.dependenciesSchema) {\n                        ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];\n                        if (!dependenciesValidator->IsValid())\n                            context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);\n                    }\n                }\n            }\n            if (context.error_handler.EndDependencyErrors())\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());\n        }\n\n        return true;\n    }\n\n    bool StartArray(Context& context) const {\n        if (!(type_ & (1 << kArraySchemaType))) {\n            DisallowedType(context, GetArrayString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n\n        context.arrayElementIndex = 0;\n        context.inArray = true;\n\n        return CreateParallelValidator(context);\n    }\n\n    bool EndArray(Context& context, SizeType elementCount) const {\n        context.inArray = false;\n        \n        if (elementCount < minItems_) {\n            context.error_handler.TooFewItems(elementCount, minItems_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());\n        }\n        \n        if (elementCount > maxItems_) {\n            context.error_handler.TooManyItems(elementCount, maxItems_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());\n        }\n\n        return true;\n    }\n\n    // Generate functions for string literal according to Ch\n#define RAPIDJSON_STRING_(name, ...) \\\n    static const ValueType& Get##name##String() {\\\n        static const Ch s[] = { __VA_ARGS__, '\\0' };\\\n        static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\\\n        return v;\\\n    }\n\n    RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')\n    RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')\n    RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')\n    RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')\n    RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')\n    RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')\n    RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')\n    RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')\n    RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')\n    RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')\n    RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')\n    RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')\n    RAPIDJSON_STRING_(Not, 'n', 'o', 't')\n    RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')\n    RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')\n    RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')\n    RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')\n    RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')\n    RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')\n    RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')\n\n#undef RAPIDJSON_STRING_\n\nprivate:\n    enum SchemaValueType {\n        kNullSchemaType,\n        kBooleanSchemaType,\n        kObjectSchemaType,\n        kArraySchemaType,\n        kStringSchemaType,\n        kNumberSchemaType,\n        kIntegerSchemaType,\n        kTotalSchemaType\n    };\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX\n        typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;\n#elif RAPIDJSON_SCHEMA_USE_STDREGEX\n        typedef std::basic_regex<Ch> RegexType;\n#else\n        typedef char RegexType;\n#endif\n\n    struct SchemaArray {\n        SchemaArray() : schemas(), count() {}\n        ~SchemaArray() { AllocatorType::Free(schemas); }\n        const SchemaType** schemas;\n        SizeType begin; // begin index of context.validators\n        SizeType count;\n    };\n\n    template <typename V1, typename V2>\n    void AddUniqueElement(V1& a, const V2& v) {\n        for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)\n            if (*itr == v)\n                return;\n        V1 c(v, *allocator_);\n        a.PushBack(c, *allocator_);\n    }\n\n    static const ValueType* GetMember(const ValueType& value, const ValueType& name) {\n        typename ValueType::ConstMemberIterator itr = value.FindMember(name);\n        return itr != value.MemberEnd() ? &(itr->value) : 0;\n    }\n\n    static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {\n        if (const ValueType* v = GetMember(value, name))\n            if (v->IsBool())\n                out = v->GetBool();\n    }\n\n    static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {\n        if (const ValueType* v = GetMember(value, name))\n            if (v->IsUint64() && v->GetUint64() <= SizeType(~0))\n                out = static_cast<SizeType>(v->GetUint64());\n    }\n\n    void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {\n        if (const ValueType* v = GetMember(value, name)) {\n            if (v->IsArray() && v->Size() > 0) {\n                PointerType q = p.Append(name, allocator_);\n                out.count = v->Size();\n                out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));\n                memset(out.schemas, 0, sizeof(Schema*)* out.count);\n                for (SizeType i = 0; i < out.count; i++)\n                    schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);\n                out.begin = validatorCount_;\n                validatorCount_ += out.count;\n            }\n        }\n    }\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX\n    template <typename ValueType>\n    RegexType* CreatePattern(const ValueType& value) {\n        if (value.IsString()) {\n            RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);\n            if (!r->IsValid()) {\n                r->~RegexType();\n                AllocatorType::Free(r);\n                r = 0;\n            }\n            return r;\n        }\n        return 0;\n    }\n\n    static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {\n        GenericRegexSearch<RegexType> rs(*pattern);\n        return rs.Search(str);\n    }\n#elif RAPIDJSON_SCHEMA_USE_STDREGEX\n    template <typename ValueType>\n    RegexType* CreatePattern(const ValueType& value) {\n        if (value.IsString()) {\n            RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));\n            try {\n                return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);\n            }\n            catch (const std::regex_error&) {\n                AllocatorType::Free(r);\n            }\n        }\n        return 0;\n    }\n\n    static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {\n        std::match_results<const Ch*> r;\n        return std::regex_search(str, str + length, r, *pattern);\n    }\n#else\n    template <typename ValueType>\n    RegexType* CreatePattern(const ValueType&) { return 0; }\n\n    static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }\n#endif // RAPIDJSON_SCHEMA_USE_STDREGEX\n\n    void AddType(const ValueType& type) {\n        if      (type == GetNullString()   ) type_ |= 1 << kNullSchemaType;\n        else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;\n        else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;\n        else if (type == GetArrayString()  ) type_ |= 1 << kArraySchemaType;\n        else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;\n        else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;\n        else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);\n    }\n\n    bool CreateParallelValidator(Context& context) const {\n        if (enum_ || context.arrayUniqueness)\n            context.hasher = context.factory.CreateHasher();\n\n        if (validatorCount_) {\n            RAPIDJSON_ASSERT(context.validators == 0);\n            context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));\n            context.validatorCount = validatorCount_;\n\n            if (allOf_.schemas)\n                CreateSchemaValidators(context, allOf_);\n\n            if (anyOf_.schemas)\n                CreateSchemaValidators(context, anyOf_);\n            \n            if (oneOf_.schemas)\n                CreateSchemaValidators(context, oneOf_);\n            \n            if (not_)\n                context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);\n            \n            if (hasSchemaDependencies_) {\n                for (SizeType i = 0; i < propertyCount_; i++)\n                    if (properties_[i].dependenciesSchema)\n                        context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);\n            }\n        }\n\n        return true;\n    }\n\n    void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {\n        for (SizeType i = 0; i < schemas.count; i++)\n            context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);\n    }\n\n    // O(n)\n    bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {\n        SizeType len = name.GetStringLength();\n        const Ch* str = name.GetString();\n        for (SizeType index = 0; index < propertyCount_; index++)\n            if (properties_[index].name.GetStringLength() == len && \n                (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))\n            {\n                *outIndex = index;\n                return true;\n            }\n        return false;\n    }\n\n    bool CheckInt(Context& context, int64_t i) const {\n        if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {\n            DisallowedType(context, GetIntegerString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n\n        if (!minimum_.IsNull()) {\n            if (minimum_.IsInt64()) {\n                if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {\n                    context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());\n                }\n            }\n            else if (minimum_.IsUint64()) {\n                context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()\n            }\n            else if (!CheckDoubleMinimum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!maximum_.IsNull()) {\n            if (maximum_.IsInt64()) {\n                if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {\n                    context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());\n                }\n            }\n            else if (maximum_.IsUint64()) { }\n                /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()\n            else if (!CheckDoubleMaximum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!multipleOf_.IsNull()) {\n            if (multipleOf_.IsUint64()) {\n                if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {\n                    context.error_handler.NotMultipleOf(i, multipleOf_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());\n                }\n            }\n            else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))\n                return false;\n        }\n\n        return true;\n    }\n\n    bool CheckUint(Context& context, uint64_t i) const {\n        if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {\n            DisallowedType(context, GetIntegerString());\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        }\n\n        if (!minimum_.IsNull()) {\n            if (minimum_.IsUint64()) {\n                if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {\n                    context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());\n                }\n            }\n            else if (minimum_.IsInt64())\n                /* do nothing */; // i >= 0 > minimum.Getint64()\n            else if (!CheckDoubleMinimum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!maximum_.IsNull()) {\n            if (maximum_.IsUint64()) {\n                if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {\n                    context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());\n                }\n            }\n            else if (maximum_.IsInt64()) {\n                context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_\n            }\n            else if (!CheckDoubleMaximum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!multipleOf_.IsNull()) {\n            if (multipleOf_.IsUint64()) {\n                if (i % multipleOf_.GetUint64() != 0) {\n                    context.error_handler.NotMultipleOf(i, multipleOf_);\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());\n                }\n            }\n            else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))\n                return false;\n        }\n\n        return true;\n    }\n\n    bool CheckDoubleMinimum(Context& context, double d) const {\n        if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {\n            context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());\n        }\n        return true;\n    }\n\n    bool CheckDoubleMaximum(Context& context, double d) const {\n        if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {\n            context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());\n        }\n        return true;\n    }\n\n    bool CheckDoubleMultipleOf(Context& context, double d) const {\n        double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());\n        double q = std::floor(a / b);\n        double r = a - q * b;\n        if (r > 0.0) {\n            context.error_handler.NotMultipleOf(d, multipleOf_);\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());\n        }\n        return true;\n    }\n\n    void DisallowedType(Context& context, const ValueType& actualType) const {\n        ErrorHandler& eh = context.error_handler;\n        eh.StartDisallowedType();\n\n        if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());\n        if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());\n        if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());\n        if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());\n        if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());\n\n        if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());\n        else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());\n\n        eh.EndDisallowedType(actualType);\n    }\n\n    struct Property {\n        Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}\n        ~Property() { AllocatorType::Free(dependencies); }\n        SValue name;\n        const SchemaType* schema;\n        const SchemaType* dependenciesSchema;\n        SizeType dependenciesValidatorIndex;\n        bool* dependencies;\n        bool required;\n    };\n\n    struct PatternProperty {\n        PatternProperty() : schema(), pattern() {}\n        ~PatternProperty() { \n            if (pattern) {\n                pattern->~RegexType();\n                AllocatorType::Free(pattern);\n            }\n        }\n        const SchemaType* schema;\n        RegexType* pattern;\n    };\n\n    AllocatorType* allocator_;\n    SValue uri_;\n    PointerType pointer_;\n    const SchemaType* typeless_;\n    uint64_t* enum_;\n    SizeType enumCount_;\n    SchemaArray allOf_;\n    SchemaArray anyOf_;\n    SchemaArray oneOf_;\n    const SchemaType* not_;\n    unsigned type_; // bitmask of kSchemaType\n    SizeType validatorCount_;\n    SizeType notValidatorIndex_;\n\n    Property* properties_;\n    const SchemaType* additionalPropertiesSchema_;\n    PatternProperty* patternProperties_;\n    SizeType patternPropertyCount_;\n    SizeType propertyCount_;\n    SizeType minProperties_;\n    SizeType maxProperties_;\n    bool additionalProperties_;\n    bool hasDependencies_;\n    bool hasRequired_;\n    bool hasSchemaDependencies_;\n\n    const SchemaType* additionalItemsSchema_;\n    const SchemaType* itemsList_;\n    const SchemaType** itemsTuple_;\n    SizeType itemsTupleCount_;\n    SizeType minItems_;\n    SizeType maxItems_;\n    bool additionalItems_;\n    bool uniqueItems_;\n\n    RegexType* pattern_;\n    SizeType minLength_;\n    SizeType maxLength_;\n\n    SValue minimum_;\n    SValue maximum_;\n    SValue multipleOf_;\n    bool exclusiveMinimum_;\n    bool exclusiveMaximum_;\n    \n    SizeType defaultValueLength_;\n};\n\ntemplate<typename Stack, typename Ch>\nstruct TokenHelper {\n    RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {\n        *documentStack.template Push<Ch>() = '/';\n        char buffer[21];\n        size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);\n        for (size_t i = 0; i < length; i++)\n            *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);\n    }\n};\n\n// Partial specialized version for char to prevent buffer copying.\ntemplate <typename Stack>\nstruct TokenHelper<Stack, char> {\n    RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {\n        if (sizeof(SizeType) == 4) {\n            char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint\n            *buffer++ = '/';\n            const char* end = internal::u32toa(index, buffer);\n             documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));\n        }\n        else {\n            char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64\n            *buffer++ = '/';\n            const char* end = internal::u64toa(index, buffer);\n            documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));\n        }\n    }\n};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// IGenericRemoteSchemaDocumentProvider\n\ntemplate <typename SchemaDocumentType>\nclass IGenericRemoteSchemaDocumentProvider {\npublic:\n    typedef typename SchemaDocumentType::Ch Ch;\n\n    virtual ~IGenericRemoteSchemaDocumentProvider() {}\n    virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericSchemaDocument\n\n//! JSON schema document.\n/*!\n    A JSON schema document is a compiled version of a JSON schema.\n    It is basically a tree of internal::Schema.\n\n    \\note This is an immutable class (i.e. its instance cannot be modified after construction).\n    \\tparam ValueT Type of JSON value (e.g. \\c Value ), which also determine the encoding.\n    \\tparam Allocator Allocator type for allocating memory of this document.\n*/\ntemplate <typename ValueT, typename Allocator = CrtAllocator>\nclass GenericSchemaDocument {\npublic:\n    typedef ValueT ValueType;\n    typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;\n    typedef Allocator AllocatorType;\n    typedef typename ValueType::EncodingType EncodingType;\n    typedef typename EncodingType::Ch Ch;\n    typedef internal::Schema<GenericSchemaDocument> SchemaType;\n    typedef GenericPointer<ValueType, Allocator> PointerType;\n    typedef GenericValue<EncodingType, Allocator> URIType;\n    friend class internal::Schema<GenericSchemaDocument>;\n    template <typename, typename, typename>\n    friend class GenericSchemaValidator;\n\n    //! Constructor.\n    /*!\n        Compile a JSON document into schema document.\n\n        \\param document A JSON document as source.\n        \\param uri The base URI of this schema document for purposes of violation reporting.\n        \\param uriLength Length of \\c name, in code points.\n        \\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.\n        \\param allocator An optional allocator instance for allocating memory. Can be null.\n    */\n    explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,\n        IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :\n        remoteProvider_(remoteProvider),\n        allocator_(allocator),\n        ownAllocator_(),\n        root_(),\n        typeless_(),\n        schemaMap_(allocator, kInitialSchemaMapSize),\n        schemaRef_(allocator, kInitialSchemaRefSize)\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();\n\n        Ch noUri[1] = {0};\n        uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);\n\n        typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));\n        new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_);\n\n        // Generate root schema, it will call CreateSchema() to create sub-schemas,\n        // And call AddRefSchema() if there are $ref.\n        CreateSchemaRecursive(&root_, PointerType(), document, document);\n\n        // Resolve $ref\n        while (!schemaRef_.Empty()) {\n            SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);\n            if (const SchemaType* s = GetSchema(refEntry->target)) {\n                if (refEntry->schema)\n                    *refEntry->schema = s;\n\n                // Create entry in map if not exist\n                if (!GetSchema(refEntry->source)) {\n                    new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);\n                }\n            }\n            else if (refEntry->schema)\n                *refEntry->schema = typeless_;\n\n            refEntry->~SchemaRefEntry();\n        }\n\n        RAPIDJSON_ASSERT(root_ != 0);\n\n        schemaRef_.ShrinkToFit(); // Deallocate all memory for ref\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :\n        remoteProvider_(rhs.remoteProvider_),\n        allocator_(rhs.allocator_),\n        ownAllocator_(rhs.ownAllocator_),\n        root_(rhs.root_),\n        typeless_(rhs.typeless_),\n        schemaMap_(std::move(rhs.schemaMap_)),\n        schemaRef_(std::move(rhs.schemaRef_)),\n        uri_(std::move(rhs.uri_))\n    {\n        rhs.remoteProvider_ = 0;\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.typeless_ = 0;\n    }\n#endif\n\n    //! Destructor\n    ~GenericSchemaDocument() {\n        while (!schemaMap_.Empty())\n            schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();\n\n        if (typeless_) {\n            typeless_->~SchemaType();\n            Allocator::Free(typeless_);\n        }\n\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    const URIType& GetURI() const { return uri_; }\n\n    //! Get the root schema.\n    const SchemaType& GetRoot() const { return *root_; }\n\nprivate:\n    //! Prohibit copying\n    GenericSchemaDocument(const GenericSchemaDocument&);\n    //! Prohibit assignment\n    GenericSchemaDocument& operator=(const GenericSchemaDocument&);\n\n    struct SchemaRefEntry {\n        SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}\n        PointerType source;\n        PointerType target;\n        const SchemaType** schema;\n    };\n\n    struct SchemaEntry {\n        SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}\n        ~SchemaEntry() {\n            if (owned) {\n                schema->~SchemaType();\n                Allocator::Free(schema);\n            }\n        }\n        PointerType pointer;\n        SchemaType* schema;\n        bool owned;\n    };\n\n    void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {\n        if (schema)\n            *schema = typeless_;\n\n        if (v.GetType() == kObjectType) {\n            const SchemaType* s = GetSchema(pointer);\n            if (!s)\n                CreateSchema(schema, pointer, v, document);\n\n            for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)\n                CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);\n        }\n        else if (v.GetType() == kArrayType)\n            for (SizeType i = 0; i < v.Size(); i++)\n                CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);\n    }\n\n    void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {\n        RAPIDJSON_ASSERT(pointer.IsValid());\n        if (v.IsObject()) {\n            if (!HandleRefSchema(pointer, schema, v, document)) {\n                SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);\n                new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);\n                if (schema)\n                    *schema = s;\n            }\n        }\n    }\n\n    bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {\n        static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\\0' };\n        static const ValueType kRefValue(kRefString, 4);\n\n        typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);\n        if (itr == v.MemberEnd())\n            return false;\n\n        if (itr->value.IsString()) {\n            SizeType len = itr->value.GetStringLength();\n            if (len > 0) {\n                const Ch* s = itr->value.GetString();\n                SizeType i = 0;\n                while (i < len && s[i] != '#') // Find the first #\n                    i++;\n\n                if (i > 0) { // Remote reference, resolve immediately\n                    if (remoteProvider_) {\n                        if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {\n                            PointerType pointer(&s[i], len - i, allocator_);\n                            if (pointer.IsValid()) {\n                                if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {\n                                    if (schema)\n                                        *schema = sc;\n                                    new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc), false, allocator_);\n                                    return true;\n                                }\n                            }\n                        }\n                    }\n                }\n                else if (s[i] == '#') { // Local reference, defer resolution\n                    PointerType pointer(&s[i], len - i, allocator_);\n                    if (pointer.IsValid()) {\n                        if (const ValueType* nv = pointer.Get(document))\n                            if (HandleRefSchema(source, schema, *nv, document))\n                                return true;\n\n                        new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    const SchemaType* GetSchema(const PointerType& pointer) const {\n        for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)\n            if (pointer == target->pointer)\n                return target->schema;\n        return 0;\n    }\n\n    PointerType GetPointer(const SchemaType* schema) const {\n        for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)\n            if (schema == target->schema)\n                return target->pointer;\n        return PointerType();\n    }\n\n    const SchemaType* GetTypeless() const { return typeless_; }\n\n    static const size_t kInitialSchemaMapSize = 64;\n    static const size_t kInitialSchemaRefSize = 64;\n\n    IRemoteSchemaDocumentProviderType* remoteProvider_;\n    Allocator *allocator_;\n    Allocator *ownAllocator_;\n    const SchemaType* root_;                //!< Root schema.\n    SchemaType* typeless_;\n    internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas\n    internal::Stack<Allocator> schemaRef_;  // Stores Pointer from $ref and schema which holds the $ref\n    URIType uri_;\n};\n\n//! GenericSchemaDocument using Value type.\ntypedef GenericSchemaDocument<Value> SchemaDocument;\n//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.\ntypedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericSchemaValidator\n\n//! JSON Schema Validator.\n/*!\n    A SAX style JSON schema validator.\n    It uses a \\c GenericSchemaDocument to validate SAX events.\n    It delegates the incoming SAX events to an output handler.\n    The default output handler does nothing.\n    It can be reused multiple times by calling \\c Reset().\n\n    \\tparam SchemaDocumentType Type of schema document.\n    \\tparam OutputHandler Type of output handler. Default handler does nothing.\n    \\tparam StateAllocator Allocator for storing the internal validation states.\n*/\ntemplate <\n    typename SchemaDocumentType,\n    typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,\n    typename StateAllocator = CrtAllocator>\nclass GenericSchemaValidator :\n    public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, \n    public internal::ISchemaValidator,\n    public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>\n{\npublic:\n    typedef typename SchemaDocumentType::SchemaType SchemaType;\n    typedef typename SchemaDocumentType::PointerType PointerType;\n    typedef typename SchemaType::EncodingType EncodingType;\n    typedef typename SchemaType::SValue SValue;\n    typedef typename EncodingType::Ch Ch;\n    typedef GenericStringRef<Ch> StringRefType;\n    typedef GenericValue<EncodingType, StateAllocator> ValueType;\n\n    //! Constructor without output handler.\n    /*!\n        \\param schemaDocument The schema document to conform to.\n        \\param allocator Optional allocator for storing internal validation states.\n        \\param schemaStackCapacity Optional initial capacity of schema path stack.\n        \\param documentStackCapacity Optional initial capacity of document path stack.\n    */\n    GenericSchemaValidator(\n        const SchemaDocumentType& schemaDocument,\n        StateAllocator* allocator = 0, \n        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,\n        size_t documentStackCapacity = kDefaultDocumentStackCapacity)\n        :\n        schemaDocument_(&schemaDocument),\n        root_(schemaDocument.GetRoot()),\n        stateAllocator_(allocator),\n        ownStateAllocator_(0),\n        schemaStack_(allocator, schemaStackCapacity),\n        documentStack_(allocator, documentStackCapacity),\n        outputHandler_(0),\n        error_(kObjectType),\n        currentError_(),\n        missingDependents_(),\n        valid_(true)\n#if RAPIDJSON_SCHEMA_VERBOSE\n        , depth_(0)\n#endif\n    {\n    }\n\n    //! Constructor with output handler.\n    /*!\n        \\param schemaDocument The schema document to conform to.\n        \\param allocator Optional allocator for storing internal validation states.\n        \\param schemaStackCapacity Optional initial capacity of schema path stack.\n        \\param documentStackCapacity Optional initial capacity of document path stack.\n    */\n    GenericSchemaValidator(\n        const SchemaDocumentType& schemaDocument,\n        OutputHandler& outputHandler,\n        StateAllocator* allocator = 0, \n        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,\n        size_t documentStackCapacity = kDefaultDocumentStackCapacity)\n        :\n        schemaDocument_(&schemaDocument),\n        root_(schemaDocument.GetRoot()),\n        stateAllocator_(allocator),\n        ownStateAllocator_(0),\n        schemaStack_(allocator, schemaStackCapacity),\n        documentStack_(allocator, documentStackCapacity),\n        outputHandler_(&outputHandler),\n        error_(kObjectType),\n        currentError_(),\n        missingDependents_(),\n        valid_(true)\n#if RAPIDJSON_SCHEMA_VERBOSE\n        , depth_(0)\n#endif\n    {\n    }\n\n    //! Destructor.\n    ~GenericSchemaValidator() {\n        Reset();\n        RAPIDJSON_DELETE(ownStateAllocator_);\n    }\n\n    //! Reset the internal states.\n    void Reset() {\n        while (!schemaStack_.Empty())\n            PopSchema();\n        documentStack_.Clear();\n        error_.SetObject();\n        currentError_.SetNull();\n        missingDependents_.SetNull();\n        valid_ = true;\n    }\n\n    //! Checks whether the current state is valid.\n    // Implementation of ISchemaValidator\n    virtual bool IsValid() const { return valid_; }\n\n    //! Gets the error object.\n    ValueType& GetError() { return error_; }\n    const ValueType& GetError() const { return error_; }\n\n    //! Gets the JSON pointer pointed to the invalid schema.\n    PointerType GetInvalidSchemaPointer() const {\n        return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();\n    }\n\n    //! Gets the keyword of invalid schema.\n    const Ch* GetInvalidSchemaKeyword() const {\n        return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;\n    }\n\n    //! Gets the JSON pointer pointed to the invalid value.\n    PointerType GetInvalidDocumentPointer() const {\n        if (documentStack_.Empty()) {\n            return PointerType();\n        }\n        else {\n            return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));\n        }\n    }\n\n    void NotMultipleOf(int64_t actual, const SValue& expected) {\n        AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);\n    }\n    void NotMultipleOf(uint64_t actual, const SValue& expected) {\n        AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);\n    }\n    void NotMultipleOf(double actual, const SValue& expected) {\n        AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);\n    }\n    void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {\n        AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,\n            exclusive ? &SchemaType::GetExclusiveMaximumString : 0);\n    }\n    void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {\n        AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,\n            exclusive ? &SchemaType::GetExclusiveMaximumString : 0);\n    }\n    void AboveMaximum(double actual, const SValue& expected, bool exclusive) {\n        AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,\n            exclusive ? &SchemaType::GetExclusiveMaximumString : 0);\n    }\n    void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {\n        AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,\n            exclusive ? &SchemaType::GetExclusiveMinimumString : 0);\n    }\n    void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {\n        AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,\n            exclusive ? &SchemaType::GetExclusiveMinimumString : 0);\n    }\n    void BelowMinimum(double actual, const SValue& expected, bool exclusive) {\n        AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,\n            exclusive ? &SchemaType::GetExclusiveMinimumString : 0);\n    }\n\n    void TooLong(const Ch* str, SizeType length, SizeType expected) {\n        AddNumberError(SchemaType::GetMaxLengthString(),\n            ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());\n    }\n    void TooShort(const Ch* str, SizeType length, SizeType expected) {\n        AddNumberError(SchemaType::GetMinLengthString(),\n            ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());\n    }\n    void DoesNotMatch(const Ch* str, SizeType length) {\n        currentError_.SetObject();\n        currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());\n        AddCurrentError(SchemaType::GetPatternString());\n    }\n\n    void DisallowedItem(SizeType index) {\n        currentError_.SetObject();\n        currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());\n        AddCurrentError(SchemaType::GetAdditionalItemsString(), true);\n    }\n    void TooFewItems(SizeType actualCount, SizeType expectedCount) {\n        AddNumberError(SchemaType::GetMinItemsString(),\n            ValueType(actualCount).Move(), SValue(expectedCount).Move());\n    }\n    void TooManyItems(SizeType actualCount, SizeType expectedCount) {\n        AddNumberError(SchemaType::GetMaxItemsString(),\n            ValueType(actualCount).Move(), SValue(expectedCount).Move());\n    }\n    void DuplicateItems(SizeType index1, SizeType index2) {\n        ValueType duplicates(kArrayType);\n        duplicates.PushBack(index1, GetStateAllocator());\n        duplicates.PushBack(index2, GetStateAllocator());\n        currentError_.SetObject();\n        currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());\n        AddCurrentError(SchemaType::GetUniqueItemsString(), true);\n    }\n\n    void TooManyProperties(SizeType actualCount, SizeType expectedCount) {\n        AddNumberError(SchemaType::GetMaxPropertiesString(),\n            ValueType(actualCount).Move(), SValue(expectedCount).Move());\n    }\n    void TooFewProperties(SizeType actualCount, SizeType expectedCount) {\n        AddNumberError(SchemaType::GetMinPropertiesString(),\n            ValueType(actualCount).Move(), SValue(expectedCount).Move());\n    }\n    void StartMissingProperties() {\n        currentError_.SetArray();\n    }\n    void AddMissingProperty(const SValue& name) {\n        currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());\n    }\n    bool EndMissingProperties() {\n        if (currentError_.Empty())\n            return false;\n        ValueType error(kObjectType);\n        error.AddMember(GetMissingString(), currentError_, GetStateAllocator());\n        currentError_ = error;\n        AddCurrentError(SchemaType::GetRequiredString());\n        return true;\n    }\n    void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {\n        for (SizeType i = 0; i < count; ++i)\n            MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());\n    }\n    void DisallowedProperty(const Ch* name, SizeType length) {\n        currentError_.SetObject();\n        currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());\n        AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true);\n    }\n\n    void StartDependencyErrors() {\n        currentError_.SetObject();\n    }\n    void StartMissingDependentProperties() {\n        missingDependents_.SetArray();\n    }\n    void AddMissingDependentProperty(const SValue& targetName) {\n        missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());\n    }\n    void EndMissingDependentProperties(const SValue& sourceName) {\n        if (!missingDependents_.Empty())\n            currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),\n                missingDependents_, GetStateAllocator());\n    }\n    void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {\n        currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),\n            static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());\n    }\n    bool EndDependencyErrors() {\n        if (currentError_.ObjectEmpty())\n            return false;\n        ValueType error(kObjectType);\n        error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());\n        currentError_ = error;\n        AddCurrentError(SchemaType::GetDependenciesString());\n        return true;\n    }\n\n    void DisallowedValue() {\n        currentError_.SetObject();\n        AddCurrentError(SchemaType::GetEnumString());\n    }\n    void StartDisallowedType() {\n        currentError_.SetArray();\n    }\n    void AddExpectedType(const typename SchemaType::ValueType& expectedType) {\n        currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());\n    }\n    void EndDisallowedType(const typename SchemaType::ValueType& actualType) {\n        ValueType error(kObjectType);\n        error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());\n        error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());\n        currentError_ = error;\n        AddCurrentError(SchemaType::GetTypeString());\n    }\n    void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {\n        for (SizeType i = 0; i < count; ++i) {\n            MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());\n        }\n    }\n    void NoneOf(ISchemaValidator** subvalidators, SizeType count) {\n        AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);\n    }\n    void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {\n        AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);\n    }\n    void Disallowed() {\n        currentError_.SetObject();\n        AddCurrentError(SchemaType::GetNotString());\n    }\n\n#define RAPIDJSON_STRING_(name, ...) \\\n    static const StringRefType& Get##name##String() {\\\n        static const Ch s[] = { __VA_ARGS__, '\\0' };\\\n        static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \\\n        return v;\\\n    }\n\n    RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')\n    RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')\n    RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')\n    RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')\n    RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')\n    RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')\n    RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')\n    RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')\n\n#undef RAPIDJSON_STRING_\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \\\nRAPIDJSON_MULTILINEMACRO_BEGIN\\\n    *documentStack_.template Push<Ch>() = '\\0';\\\n    documentStack_.template Pop<Ch>(1);\\\n    internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\\\nRAPIDJSON_MULTILINEMACRO_END\n#else\n#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()\n#endif\n\n#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\\\n    if (!valid_) return false; \\\n    if (!BeginValue() || !CurrentSchema().method arg1) {\\\n        RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\\\n        return valid_ = false;\\\n    }\n\n#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\\\n    for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\\\n        if (context->hasher)\\\n            static_cast<HasherType*>(context->hasher)->method arg2;\\\n        if (context->validators)\\\n            for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\\\n                static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\\\n        if (context->patternPropertiesValidators)\\\n            for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\\\n                static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\\\n    }\n\n#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\\\n    return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)\n\n#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \\\n    RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\\\n    RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\\\n    RAPIDJSON_SCHEMA_HANDLE_END_     (method, arg2)\n\n    bool Null()             { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null,   (CurrentContext()), ( )); }\n    bool Bool(bool b)       { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool,   (CurrentContext(), b), (b)); }\n    bool Int(int i)         { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int,    (CurrentContext(), i), (i)); }\n    bool Uint(unsigned u)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint,   (CurrentContext(), u), (u)); }\n    bool Int64(int64_t i)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64,  (CurrentContext(), i), (i)); }\n    bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }\n    bool Double(double d)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }\n    bool RawNumber(const Ch* str, SizeType length, bool copy)\n                                    { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }\n    bool String(const Ch* str, SizeType length, bool copy)\n                                    { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }\n\n    bool StartObject() {\n        RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());\n        return valid_ = !outputHandler_ || outputHandler_->StartObject();\n    }\n    \n    bool Key(const Ch* str, SizeType len, bool copy) {\n        if (!valid_) return false;\n        AppendToken(str, len);\n        if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));\n        return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);\n    }\n    \n    bool EndObject(SizeType memberCount) { \n        if (!valid_) return false;\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));\n        if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;\n        RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));\n    }\n\n    bool StartArray() {\n        RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());\n        return valid_ = !outputHandler_ || outputHandler_->StartArray();\n    }\n    \n    bool EndArray(SizeType elementCount) {\n        if (!valid_) return false;\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));\n        if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;\n        RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));\n    }\n\n#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_\n#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_\n#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_\n#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_\n\n    // Implementation of ISchemaStateFactory<SchemaType>\n    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {\n        return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),\n#if RAPIDJSON_SCHEMA_VERBOSE\n        depth_ + 1,\n#endif\n        &GetStateAllocator());\n    }\n\n    virtual void DestroySchemaValidator(ISchemaValidator* validator) {\n        GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);\n        v->~GenericSchemaValidator();\n        StateAllocator::Free(v);\n    }\n\n    virtual void* CreateHasher() {\n        return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());\n    }\n\n    virtual uint64_t GetHashCode(void* hasher) {\n        return static_cast<HasherType*>(hasher)->GetHashCode();\n    }\n\n    virtual void DestroryHasher(void* hasher) {\n        HasherType* h = static_cast<HasherType*>(hasher);\n        h->~HasherType();\n        StateAllocator::Free(h);\n    }\n\n    virtual void* MallocState(size_t size) {\n        return GetStateAllocator().Malloc(size);\n    }\n\n    virtual void FreeState(void* p) {\n        StateAllocator::Free(p);\n    }\n\nprivate:\n    typedef typename SchemaType::Context Context;\n    typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;\n    typedef internal::Hasher<EncodingType, StateAllocator> HasherType;\n\n    GenericSchemaValidator( \n        const SchemaDocumentType& schemaDocument,\n        const SchemaType& root,\n        const char* basePath, size_t basePathSize,\n#if RAPIDJSON_SCHEMA_VERBOSE\n        unsigned depth,\n#endif\n        StateAllocator* allocator = 0,\n        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,\n        size_t documentStackCapacity = kDefaultDocumentStackCapacity)\n        :\n        schemaDocument_(&schemaDocument),\n        root_(root),\n        stateAllocator_(allocator),\n        ownStateAllocator_(0),\n        schemaStack_(allocator, schemaStackCapacity),\n        documentStack_(allocator, documentStackCapacity),\n        outputHandler_(0),\n        error_(kObjectType),\n        currentError_(),\n        missingDependents_(),\n        valid_(true)\n#if RAPIDJSON_SCHEMA_VERBOSE\n        , depth_(depth)\n#endif\n    {\n        if (basePath && basePathSize)\n            memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);\n    }\n\n    StateAllocator& GetStateAllocator() {\n        if (!stateAllocator_)\n            stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();\n        return *stateAllocator_;\n    }\n\n    bool BeginValue() {\n        if (schemaStack_.Empty())\n            PushSchema(root_);\n        else {\n            if (CurrentContext().inArray)\n                internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);\n\n            if (!CurrentSchema().BeginValue(CurrentContext()))\n                return false;\n\n            SizeType count = CurrentContext().patternPropertiesSchemaCount;\n            const SchemaType** sa = CurrentContext().patternPropertiesSchemas;\n            typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;\n            bool valueUniqueness = CurrentContext().valueUniqueness;\n            RAPIDJSON_ASSERT(CurrentContext().valueSchema);\n            PushSchema(*CurrentContext().valueSchema);\n\n            if (count > 0) {\n                CurrentContext().objectPatternValidatorType = patternValidatorType;\n                ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;\n                SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;\n                va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));\n                for (SizeType i = 0; i < count; i++)\n                    va[validatorCount++] = CreateSchemaValidator(*sa[i]);\n            }\n\n            CurrentContext().arrayUniqueness = valueUniqueness;\n        }\n        return true;\n    }\n\n    bool EndValue() {\n        if (!CurrentSchema().EndValue(CurrentContext()))\n            return false;\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n        GenericStringBuffer<EncodingType> sb;\n        schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);\n\n        *documentStack_.template Push<Ch>() = '\\0';\n        documentStack_.template Pop<Ch>(1);\n        internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());\n#endif\n\n        uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;\n        \n        PopSchema();\n\n        if (!schemaStack_.Empty()) {\n            Context& context = CurrentContext();\n            if (context.valueUniqueness) {\n                HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);\n                if (!a)\n                    CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);\n                for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)\n                    if (itr->GetUint64() == h) {\n                        DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());\n                        RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());\n                    }\n                a->PushBack(h, GetStateAllocator());\n            }\n        }\n\n        // Remove the last token of document pointer\n        while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')\n            ;\n\n        return true;\n    }\n\n    void AppendToken(const Ch* str, SizeType len) {\n        documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters\n        *documentStack_.template PushUnsafe<Ch>() = '/';\n        for (SizeType i = 0; i < len; i++) {\n            if (str[i] == '~') {\n                *documentStack_.template PushUnsafe<Ch>() = '~';\n                *documentStack_.template PushUnsafe<Ch>() = '0';\n            }\n            else if (str[i] == '/') {\n                *documentStack_.template PushUnsafe<Ch>() = '~';\n                *documentStack_.template PushUnsafe<Ch>() = '1';\n            }\n            else\n                *documentStack_.template PushUnsafe<Ch>() = str[i];\n        }\n    }\n\n    RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema); }\n    \n    RAPIDJSON_FORCEINLINE void PopSchema() {\n        Context* c = schemaStack_.template Pop<Context>(1);\n        if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {\n            a->~HashCodeArray();\n            StateAllocator::Free(a);\n        }\n        c->~Context();\n    }\n\n    void AddErrorLocation(ValueType& result, bool parent) {\n        GenericStringBuffer<EncodingType> sb;\n        PointerType instancePointer = GetInvalidDocumentPointer();\n        ((parent && instancePointer.GetTokenCount() > 0)\n            ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)\n            : instancePointer).StringifyUriFragment(sb);\n        ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),\n            GetStateAllocator());\n        result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());\n        sb.Clear();\n        memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),\n            CurrentSchema().GetURI().GetString(),\n            CurrentSchema().GetURI().GetStringLength() * sizeof(Ch));\n        GetInvalidSchemaPointer().StringifyUriFragment(sb);\n        ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),\n            GetStateAllocator());\n        result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());\n    }\n\n    void AddError(ValueType& keyword, ValueType& error) {\n        typename ValueType::MemberIterator member = error_.FindMember(keyword);\n        if (member == error_.MemberEnd())\n            error_.AddMember(keyword, error, GetStateAllocator());\n        else {\n            if (member->value.IsObject()) {\n                ValueType errors(kArrayType);\n                errors.PushBack(member->value, GetStateAllocator());\n                member->value = errors;\n            }\n            member->value.PushBack(error, GetStateAllocator());\n        }\n    }\n\n    void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) {\n        AddErrorLocation(currentError_, parent);\n        AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_);\n    }\n\n    void MergeError(ValueType& other) {\n        for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {\n            AddError(it->name, it->value);\n        }\n    }\n\n    void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected,\n        const typename SchemaType::ValueType& (*exclusive)() = 0) {\n        currentError_.SetObject();\n        currentError_.AddMember(GetActualString(), actual, GetStateAllocator());\n        currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());\n        if (exclusive)\n            currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());\n        AddCurrentError(keyword);\n    }\n\n    void AddErrorArray(const typename SchemaType::ValueType& keyword,\n        ISchemaValidator** subvalidators, SizeType count) {\n        ValueType errors(kArrayType);\n        for (SizeType i = 0; i < count; ++i)\n            errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());\n        currentError_.SetObject();\n        currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());\n        AddCurrentError(keyword);\n    }\n\n    const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }\n    Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }\n    const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }\n\n    static const size_t kDefaultSchemaStackCapacity = 1024;\n    static const size_t kDefaultDocumentStackCapacity = 256;\n    const SchemaDocumentType* schemaDocument_;\n    const SchemaType& root_;\n    StateAllocator* stateAllocator_;\n    StateAllocator* ownStateAllocator_;\n    internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)\n    internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)\n    OutputHandler* outputHandler_;\n    ValueType error_;\n    ValueType currentError_;\n    ValueType missingDependents_;\n    bool valid_;\n#if RAPIDJSON_SCHEMA_VERBOSE\n    unsigned depth_;\n#endif\n};\n\ntypedef GenericSchemaValidator<SchemaDocument> SchemaValidator;\n\n///////////////////////////////////////////////////////////////////////////////\n// SchemaValidatingReader\n\n//! A helper class for parsing with validation.\n/*!\n    This helper class is a functor, designed as a parameter of \\ref GenericDocument::Populate().\n\n    \\tparam parseFlags Combination of \\ref ParseFlag.\n    \\tparam InputStream Type of input stream, implementing Stream concept.\n    \\tparam SourceEncoding Encoding of the input stream.\n    \\tparam SchemaDocumentType Type of schema document.\n    \\tparam StackAllocator Allocator type for stack.\n*/\ntemplate <\n    unsigned parseFlags,\n    typename InputStream,\n    typename SourceEncoding,\n    typename SchemaDocumentType = SchemaDocument,\n    typename StackAllocator = CrtAllocator>\nclass SchemaValidatingReader {\npublic:\n    typedef typename SchemaDocumentType::PointerType PointerType;\n    typedef typename InputStream::Ch Ch;\n    typedef GenericValue<SourceEncoding, StackAllocator> ValueType;\n\n    //! Constructor\n    /*!\n        \\param is Input stream.\n        \\param sd Schema document.\n    */\n    SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {}\n\n    template <typename Handler>\n    bool operator()(Handler& handler) {\n        GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;\n        GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);\n        parseResult_ = reader.template Parse<parseFlags>(is_, validator);\n\n        isValid_ = validator.IsValid();\n        if (isValid_) {\n            invalidSchemaPointer_ = PointerType();\n            invalidSchemaKeyword_ = 0;\n            invalidDocumentPointer_ = PointerType();\n            error_.SetObject();\n        }\n        else {\n            invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();\n            invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();\n            invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();\n            error_.CopyFrom(validator.GetError(), allocator_);\n        }\n\n        return parseResult_;\n    }\n\n    const ParseResult& GetParseResult() const { return parseResult_; }\n    bool IsValid() const { return isValid_; }\n    const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }\n    const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }\n    const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }\n    const ValueType& GetError() const { return error_; }\n\nprivate:\n    InputStream& is_;\n    const SchemaDocumentType& sd_;\n\n    ParseResult parseResult_;\n    PointerType invalidSchemaPointer_;\n    const Ch* invalidSchemaKeyword_;\n    PointerType invalidDocumentPointer_;\n    StackAllocator allocator_;\n    ValueType error_;\n    bool isValid_;\n};\n\nRAPIDJSON_NAMESPACE_END\nRAPIDJSON_DIAG_POP\n\n#endif // RAPIDJSON_SCHEMA_H_\n"
  },
  {
    "path": "src/json/rapidjson/stream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#include \"rapidjson.h\"\n\n#ifndef RAPIDJSON_STREAM_H_\n#define RAPIDJSON_STREAM_H_\n\n#include \"encodings.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n//  Stream\n\n/*! \\class rapidjson::Stream\n    \\brief Concept for reading and writing characters.\n\n    For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().\n\n    For write-only stream, only need to implement Put() and Flush().\n\n\\code\nconcept Stream {\n    typename Ch;    //!< Character type of the stream.\n\n    //! Read the current character from stream without moving the read cursor.\n    Ch Peek() const;\n\n    //! Read the current character from stream and moving the read cursor to next character.\n    Ch Take();\n\n    //! Get the current read cursor.\n    //! \\return Number of characters read from start.\n    size_t Tell();\n\n    //! Begin writing operation at the current read pointer.\n    //! \\return The begin writer pointer.\n    Ch* PutBegin();\n\n    //! Write a character.\n    void Put(Ch c);\n\n    //! Flush the buffer.\n    void Flush();\n\n    //! End the writing operation.\n    //! \\param begin The begin write pointer returned by PutBegin().\n    //! \\return Number of characters written.\n    size_t PutEnd(Ch* begin);\n}\n\\endcode\n*/\n\n//! Provides additional information for stream.\n/*!\n    By using traits pattern, this type provides a default configuration for stream.\n    For custom stream, this type can be specialized for other configuration.\n    See TEST(Reader, CustomStringStream) in readertest.cpp for example.\n*/\ntemplate<typename Stream>\nstruct StreamTraits {\n    //! Whether to make local copy of stream for optimization during parsing.\n    /*!\n        By default, for safety, streams do not use local copy optimization.\n        Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.\n    */\n    enum { copyOptimization = 0 };\n};\n\n//! Reserve n characters for writing to a stream.\ntemplate<typename Stream>\ninline void PutReserve(Stream& stream, size_t count) {\n    (void)stream;\n    (void)count;\n}\n\n//! Write character to a stream, presuming buffer is reserved.\ntemplate<typename Stream>\ninline void PutUnsafe(Stream& stream, typename Stream::Ch c) {\n    stream.Put(c);\n}\n\n//! Put N copies of a character to a stream.\ntemplate<typename Stream, typename Ch>\ninline void PutN(Stream& stream, Ch c, size_t n) {\n    PutReserve(stream, n);\n    for (size_t i = 0; i < n; i++)\n        PutUnsafe(stream, c);\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericStreamWrapper\n\n//! A Stream Wrapper\n/*! \\tThis string stream is a wrapper for any stream by just forwarding any\n    \\treceived message to the origin stream.\n    \\note implements Stream concept\n*/\n\n#if defined(_MSC_VER) && _MSC_VER <= 1800\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\nRAPIDJSON_DIAG_OFF(4512)  // assignment operator could not be generated\n#endif\n\ntemplate <typename InputStream, typename Encoding = UTF8<> >\nclass GenericStreamWrapper {\npublic:\n    typedef typename Encoding::Ch Ch;\n    GenericStreamWrapper(InputStream& is): is_(is) {}\n\n    Ch Peek() const { return is_.Peek(); }\n    Ch Take() { return is_.Take(); }\n    size_t Tell() { return is_.Tell(); }\n    Ch* PutBegin() { return is_.PutBegin(); }\n    void Put(Ch ch) { is_.Put(ch); }\n    void Flush() { is_.Flush(); }\n    size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }\n\n    // wrapper for MemoryStream\n    const Ch* Peek4() const { return is_.Peek4(); }\n\n    // wrapper for AutoUTFInputStream\n    UTFType GetType() const { return is_.GetType(); }\n    bool HasBOM() const { return is_.HasBOM(); }\n\nprotected:\n    InputStream& is_;\n};\n\n#if defined(_MSC_VER) && _MSC_VER <= 1800\nRAPIDJSON_DIAG_POP\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// StringStream\n\n//! Read-only string stream.\n/*! \\note implements Stream concept\n*/\ntemplate <typename Encoding>\nstruct GenericStringStream {\n    typedef typename Encoding::Ch Ch;\n\n    GenericStringStream(const Ch *src) : src_(src), head_(src) {}\n\n    Ch Peek() const { return *src_; }\n    Ch Take() { return *src_++; }\n    size_t Tell() const { return static_cast<size_t>(src_ - head_); }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    const Ch* src_;     //!< Current read position.\n    const Ch* head_;    //!< Original head of the string.\n};\n\ntemplate <typename Encoding>\nstruct StreamTraits<GenericStringStream<Encoding> > {\n    enum { copyOptimization = 1 };\n};\n\n//! String stream with UTF8 encoding.\ntypedef GenericStringStream<UTF8<> > StringStream;\n\n///////////////////////////////////////////////////////////////////////////////\n// InsituStringStream\n\n//! A read-write string stream.\n/*! This string stream is particularly designed for in-situ parsing.\n    \\note implements Stream concept\n*/\ntemplate <typename Encoding>\nstruct GenericInsituStringStream {\n    typedef typename Encoding::Ch Ch;\n\n    GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}\n\n    // Read\n    Ch Peek() { return *src_; }\n    Ch Take() { return *src_++; }\n    size_t Tell() { return static_cast<size_t>(src_ - head_); }\n\n    // Write\n    void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }\n\n    Ch* PutBegin() { return dst_ = src_; }\n    size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }\n    void Flush() {}\n\n    Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }\n    void Pop(size_t count) { dst_ -= count; }\n\n    Ch* src_;\n    Ch* dst_;\n    Ch* head_;\n};\n\ntemplate <typename Encoding>\nstruct StreamTraits<GenericInsituStringStream<Encoding> > {\n    enum { copyOptimization = 1 };\n};\n\n//! Insitu string stream with UTF8 encoding.\ntypedef GenericInsituStringStream<UTF8<> > InsituStringStream;\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STREAM_H_\n"
  },
  {
    "path": "src/json/rapidjson/stringbuffer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_STRINGBUFFER_H_\n#define RAPIDJSON_STRINGBUFFER_H_\n\n#include \"stream.h\"\n#include \"src/json/rapidjson/internal/stack.h\"\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#include <utility> // std::move\n#endif\n\n#include \"src/json/rapidjson/internal/stack.h\"\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory output stream.\n/*!\n    \\tparam Encoding Encoding of the stream.\n    \\tparam Allocator type for allocating memory buffer.\n    \\note implements Stream concept\n*/\ntemplate <typename Encoding, typename Allocator = CrtAllocator>\nclass GenericStringBuffer {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}\n    GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {\n        if (&rhs != this)\n            stack_ = std::move(rhs.stack_);\n        return *this;\n    }\n#endif\n\n    void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n    void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }\n    void Flush() {}\n\n    void Clear() { stack_.Clear(); }\n    void ShrinkToFit() {\n        // Push and pop a null terminator. This is safe.\n        *stack_.template Push<Ch>() = '\\0';\n        stack_.ShrinkToFit();\n        stack_.template Pop<Ch>(1);\n    }\n\n    void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }\n    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }\n    Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }\n    void Pop(size_t count) { stack_.template Pop<Ch>(count); }\n\n    const Ch* GetString() const {\n        // Push and pop a null terminator. This is safe.\n        *stack_.template Push<Ch>() = '\\0';\n        stack_.template Pop<Ch>(1);\n\n        return stack_.template Bottom<Ch>();\n    }\n\n    //! Get the size of string in bytes in the string buffer.\n    size_t GetSize() const { return stack_.GetSize(); }\n\n    //! Get the length of string in Ch in the string buffer.\n    size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }\n\n    static const size_t kDefaultCapacity = 256;\n    mutable internal::Stack<Allocator> stack_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    GenericStringBuffer(const GenericStringBuffer&);\n    GenericStringBuffer& operator=(const GenericStringBuffer&);\n};\n\n//! String buffer with UTF8 encoding\ntypedef GenericStringBuffer<UTF8<> > StringBuffer;\n\ntemplate<typename Encoding, typename Allocator>\ninline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {\n    stream.Reserve(count);\n}\n\ntemplate<typename Encoding, typename Allocator>\ninline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {\n    stream.PutUnsafe(c);\n}\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {\n    std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_STRINGBUFFER_H_\n"
  },
  {
    "path": "src/json/rapidjson/writer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_WRITER_H_\n#define RAPIDJSON_WRITER_H_\n\n#include \"stream.h\"\n#include \"src/json/rapidjson/internal/meta.h\"\n#include \"src/json/rapidjson/internal/stack.h\"\n#include \"src/json/rapidjson/internal/strfunc.h\"\n#include \"src/json/rapidjson/internal/dtoa.h\"\n#include \"src/json/rapidjson/internal/itoa.h\"\n#include \"stringbuffer.h\"\n#include <new>      // placement new\n\n#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)\n#include <intrin.h>\n#pragma intrinsic(_BitScanForward)\n#endif\n#ifdef RAPIDJSON_SSE42\n#include <nmmintrin.h>\n#elif defined(RAPIDJSON_SSE2)\n#include <emmintrin.h>\n#elif defined(RAPIDJSON_NEON)\n#include <arm_neon.h>\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(unreachable-code)\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#elif defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127) // conditional expression is constant\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// WriteFlag\n\n/*! \\def RAPIDJSON_WRITE_DEFAULT_FLAGS \n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-defined kWriteDefaultFlags definition.\n\n    User can define this as any \\c WriteFlag combinations.\n*/\n#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS\n#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags\n#endif\n\n//! Combination of writeFlags\nenum WriteFlag {\n    kWriteNoFlags = 0,              //!< No flags are set.\n    kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.\n    kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN.\n    kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS\n};\n\n//! JSON writer\n/*! Writer implements the concept Handler.\n    It generates JSON text by events to an output os.\n\n    User may programmatically calls the functions of a writer to generate JSON text.\n\n    On the other side, a writer can also be passed to objects that generates events, \n\n    for example Reader::Parse() and Document::Accept().\n\n    \\tparam OutputStream Type of output stream.\n    \\tparam SourceEncoding Encoding of source string.\n    \\tparam TargetEncoding Encoding of output stream.\n    \\tparam StackAllocator Type of allocator for allocating memory of stack.\n    \\note implements Handler concept\n*/\ntemplate<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>\nclass Writer {\npublic:\n    typedef typename SourceEncoding::Ch Ch;\n\n    static const int kDefaultMaxDecimalPlaces = 324;\n\n    //! Constructor\n    /*! \\param os Output stream.\n        \\param stackAllocator User supplied allocator. If it is null, it will create a private one.\n        \\param levelDepth Initial capacity of stack.\n    */\n    explicit\n    Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : \n        os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}\n\n    explicit\n    Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :\n        os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Writer(Writer&& rhs) :\n        os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {\n        rhs.os_ = 0;\n    }\n#endif\n\n    //! Reset the writer with a new stream.\n    /*!\n        This function reset the writer with a new stream and default settings,\n        in order to make a Writer object reusable for output multiple JSONs.\n\n        \\param os New output stream.\n        \\code\n        Writer<OutputStream> writer(os1);\n        writer.StartObject();\n        // ...\n        writer.EndObject();\n\n        writer.Reset(os2);\n        writer.StartObject();\n        // ...\n        writer.EndObject();\n        \\endcode\n    */\n    void Reset(OutputStream& os) {\n        os_ = &os;\n        hasRoot_ = false;\n        level_stack_.Clear();\n    }\n\n    //! Checks whether the output is a complete JSON.\n    /*!\n        A complete JSON has a complete root object or array.\n    */\n    bool IsComplete() const {\n        return hasRoot_ && level_stack_.Empty();\n    }\n\n    int GetMaxDecimalPlaces() const {\n        return maxDecimalPlaces_;\n    }\n\n    //! Sets the maximum number of decimal places for double output.\n    /*!\n        This setting truncates the output with specified number of decimal places.\n\n        For example, \n\n        \\code\n        writer.SetMaxDecimalPlaces(3);\n        writer.StartArray();\n        writer.Double(0.12345);                 // \"0.123\"\n        writer.Double(0.0001);                  // \"0.0\"\n        writer.Double(1.234567890123456e30);    // \"1.234567890123456e30\" (do not truncate significand for positive exponent)\n        writer.Double(1.23e-4);                 // \"0.0\"                  (do truncate significand for negative exponent)\n        writer.EndArray();\n        \\endcode\n\n        The default setting does not truncate any decimal places. You can restore to this setting by calling\n        \\code\n        writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);\n        \\endcode\n    */\n    void SetMaxDecimalPlaces(int maxDecimalPlaces) {\n        maxDecimalPlaces_ = maxDecimalPlaces;\n    }\n\n    /*!@name Implementation of Handler\n        \\see Handler\n    */\n    //@{\n\n    bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }\n    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }\n    bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); }\n    bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); }\n    bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }\n    bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }\n\n    //! Writes the given \\c double value to the stream\n    /*!\n        \\param d The value to be written.\n        \\return Whether it is succeed.\n    */\n    bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); }\n\n    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {\n        RAPIDJSON_ASSERT(str != 0);\n        (void)copy;\n        Prefix(kNumberType);\n        return EndValue(WriteString(str, length));\n    }\n\n    bool String(const Ch* str, SizeType length, bool copy = false) {\n        RAPIDJSON_ASSERT(str != 0);\n        (void)copy;\n        Prefix(kStringType);\n        return EndValue(WriteString(str, length));\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool String(const std::basic_string<Ch>& str) {\n        return String(str.data(), SizeType(str.size()));\n    }\n#endif\n\n    bool StartObject() {\n        Prefix(kObjectType);\n        new (level_stack_.template Push<Level>()) Level(false);\n        return WriteStartObject();\n    }\n\n    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool Key(const std::basic_string<Ch>& str)\n    {\n      return Key(str.data(), SizeType(str.size()));\n    }\n#endif\n\t\n    bool EndObject(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object\n        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object\n        RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value\n        level_stack_.template Pop<Level>(1);\n        return EndValue(WriteEndObject());\n    }\n\n    bool StartArray() {\n        Prefix(kArrayType);\n        new (level_stack_.template Push<Level>()) Level(true);\n        return WriteStartArray();\n    }\n\n    bool EndArray(SizeType elementCount = 0) {\n        (void)elementCount;\n        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);\n        level_stack_.template Pop<Level>(1);\n        return EndValue(WriteEndArray());\n    }\n    //@}\n\n    /*! @name Convenience extensions */\n    //@{\n\n    //! Simpler but slower overload.\n    bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }\n    bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }\n    \n    //@}\n\n    //! Write a raw JSON value.\n    /*!\n        For user to write a stringified JSON as a value.\n\n        \\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.\n        \\param length Length of the json.\n        \\param type Type of the root of json.\n    */\n    bool RawValue(const Ch* json, size_t length, Type type) {\n        RAPIDJSON_ASSERT(json != 0);\n        Prefix(type);\n        return EndValue(WriteRawValue(json, length));\n    }\n\n    //! Flush the output stream.\n    /*!\n        Allows the user to flush the output stream immediately.\n     */\n    void Flush() {\n        os_->Flush();\n    }\n\nprotected:\n    //! Information for each nested level\n    struct Level {\n        Level(bool inArray_) : valueCount(0), inArray(inArray_) {}\n        size_t valueCount;  //!< number of values in this level\n        bool inArray;       //!< true if in array, otherwise in object\n    };\n\n    static const size_t kDefaultLevelDepth = 32;\n\n    bool WriteNull()  {\n        PutReserve(*os_, 4);\n        PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;\n    }\n\n    bool WriteBool(bool b)  {\n        if (b) {\n            PutReserve(*os_, 4);\n            PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');\n        }\n        else {\n            PutReserve(*os_, 5);\n            PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');\n        }\n        return true;\n    }\n\n    bool WriteInt(int i) {\n        char buffer[11];\n        const char* end = internal::i32toa(i, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (const char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));\n        return true;\n    }\n\n    bool WriteUint(unsigned u) {\n        char buffer[10];\n        const char* end = internal::u32toa(u, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (const char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));\n        return true;\n    }\n\n    bool WriteInt64(int64_t i64) {\n        char buffer[21];\n        const char* end = internal::i64toa(i64, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (const char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));\n        return true;\n    }\n\n    bool WriteUint64(uint64_t u64) {\n        char buffer[20];\n        char* end = internal::u64toa(u64, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));\n        return true;\n    }\n\n    bool WriteDouble(double d) {\n        if (internal::Double(d).IsNanOrInf()) {\n            if (!(writeFlags & kWriteNanAndInfFlag))\n                return false;\n            if (internal::Double(d).IsNan()) {\n                PutReserve(*os_, 3);\n                PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');\n                return true;\n            }\n            if (internal::Double(d).Sign()) {\n                PutReserve(*os_, 9);\n                PutUnsafe(*os_, '-');\n            }\n            else\n                PutReserve(*os_, 8);\n            PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');\n            PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');\n            return true;\n        }\n\n        char buffer[25];\n        char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));\n        return true;\n    }\n\n    bool WriteString(const Ch* str, SizeType length)  {\n        static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n        static const char escape[256] = {\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n            //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F\n            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00\n            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10\n              0,   0, '\"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20\n            Z16, Z16,                                                                       // 30~4F\n              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\\\',   0,   0,   0, // 50\n            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF\n#undef Z16\n        };\n\n        if (TargetEncoding::supportUnicode)\n            PutReserve(*os_, 2 + length * 6); // \"\\uxxxx...\"\n        else\n            PutReserve(*os_, 2 + length * 12);  // \"\\uxxxx\\uyyyy...\"\n\n        PutUnsafe(*os_, '\\\"');\n        GenericStringStream<SourceEncoding> is(str);\n        while (ScanWriteUnescapedString(is, length)) {\n            const Ch c = is.Peek();\n            if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {\n                // Unicode escaping\n                unsigned codepoint;\n                if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))\n                    return false;\n                PutUnsafe(*os_, '\\\\');\n                PutUnsafe(*os_, 'u');\n                if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {\n                    PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);\n                    PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]);\n                    PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]);\n                    PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]);\n                }\n                else {\n                    RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);\n                    // Surrogate pair\n                    unsigned s = codepoint - 0x010000;\n                    unsigned lead = (s >> 10) + 0xD800;\n                    unsigned trail = (s & 0x3FF) + 0xDC00;\n                    PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);\n                    PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]);\n                    PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]);\n                    PutUnsafe(*os_, hexDigits[(lead      ) & 15]);\n                    PutUnsafe(*os_, '\\\\');\n                    PutUnsafe(*os_, 'u');\n                    PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);\n                    PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]);\n                    PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]);\n                    PutUnsafe(*os_, hexDigits[(trail      ) & 15]);                    \n                }\n            }\n            else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  {\n                is.Take();\n                PutUnsafe(*os_, '\\\\');\n                PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));\n                if (escape[static_cast<unsigned char>(c)] == 'u') {\n                    PutUnsafe(*os_, '0');\n                    PutUnsafe(*os_, '0');\n                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);\n                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);\n                }\n            }\n            else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? \n                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :\n                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))\n                return false;\n        }\n        PutUnsafe(*os_, '\\\"');\n        return true;\n    }\n\n    bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {\n        return RAPIDJSON_LIKELY(is.Tell() < length);\n    }\n\n    bool WriteStartObject() { os_->Put('{'); return true; }\n    bool WriteEndObject()   { os_->Put('}'); return true; }\n    bool WriteStartArray()  { os_->Put('['); return true; }\n    bool WriteEndArray()    { os_->Put(']'); return true; }\n\n    bool WriteRawValue(const Ch* json, size_t length) {\n        PutReserve(*os_, length);\n        GenericStringStream<SourceEncoding> is(json);\n        while (RAPIDJSON_LIKELY(is.Tell() < length)) {\n            RAPIDJSON_ASSERT(is.Peek() != '\\0');\n            if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? \n                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :\n                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))\n                return false;\n        }\n        return true;\n    }\n\n    void Prefix(Type type) {\n        (void)type;\n        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root\n            Level* level = level_stack_.template Top<Level>();\n            if (level->valueCount > 0) {\n                if (level->inArray) \n                    os_->Put(','); // add comma if it is not the first element in array\n                else  // in object\n                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');\n            }\n            if (!level->inArray && level->valueCount % 2 == 0)\n                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n            level->valueCount++;\n        }\n        else {\n            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.\n            hasRoot_ = true;\n        }\n    }\n\n    // Flush the value if it is the top level one.\n    bool EndValue(bool ret) {\n        if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text\n            Flush();\n        return ret;\n    }\n\n    OutputStream* os_;\n    internal::Stack<StackAllocator> level_stack_;\n    int maxDecimalPlaces_;\n    bool hasRoot_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    Writer(const Writer&);\n    Writer& operator=(const Writer&);\n};\n\n// Full specialization for StringStream to prevent memory copying\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteInt(int i) {\n    char *buffer = os_->Push(11);\n    const char* end = internal::i32toa(i, buffer);\n    os_->Pop(static_cast<size_t>(11 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteUint(unsigned u) {\n    char *buffer = os_->Push(10);\n    const char* end = internal::u32toa(u, buffer);\n    os_->Pop(static_cast<size_t>(10 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {\n    char *buffer = os_->Push(21);\n    const char* end = internal::i64toa(i64, buffer);\n    os_->Pop(static_cast<size_t>(21 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {\n    char *buffer = os_->Push(20);\n    const char* end = internal::u64toa(u, buffer);\n    os_->Pop(static_cast<size_t>(20 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteDouble(double d) {\n    if (internal::Double(d).IsNanOrInf()) {\n        // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).\n        if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))\n            return false;\n        if (internal::Double(d).IsNan()) {\n            PutReserve(*os_, 3);\n            PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');\n            return true;\n        }\n        if (internal::Double(d).Sign()) {\n            PutReserve(*os_, 9);\n            PutUnsafe(*os_, '-');\n        }\n        else\n            PutReserve(*os_, 8);\n        PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');\n        PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');\n        return true;\n    }\n    \n    char *buffer = os_->Push(25);\n    char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);\n    os_->Pop(static_cast<size_t>(25 - (end - buffer)));\n    return true;\n}\n\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)\ntemplate<>\ninline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {\n    if (length < 16)\n        return RAPIDJSON_LIKELY(is.Tell() < length);\n\n    if (!RAPIDJSON_LIKELY(is.Tell() < length))\n        return false;\n\n    const char* p = is.src_;\n    const char* end = is.head_ + length;\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));\n    if (nextAligned > end)\n        return true;\n\n    while (p != nextAligned)\n        if (*p < 0x20 || *p == '\\\"' || *p == '\\\\') {\n            is.src_ = p;\n            return RAPIDJSON_LIKELY(is.Tell() < length);\n        }\n        else\n            os_->PutUnsafe(*p++);\n\n    // The rest of string using SIMD\n    static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n    static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n    static const char space[16]  = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };\n    const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n    const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n    const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n    for (; p != endAligned; p += 16) {\n        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n        const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n        const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n        const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F\n        const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n        unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n        if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n            SizeType len;\n#ifdef _MSC_VER         // Find the index of first escaped\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            len = offset;\n#else\n            len = static_cast<SizeType>(__builtin_ffs(r) - 1);\n#endif\n            char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));\n            for (size_t i = 0; i < len; i++)\n                q[i] = p[i];\n\n            p += len;\n            break;\n        }\n        _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);\n    }\n\n    is.src_ = p;\n    return RAPIDJSON_LIKELY(is.Tell() < length);\n}\n#elif defined(RAPIDJSON_NEON)\ntemplate<>\ninline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {\n    if (length < 16)\n        return RAPIDJSON_LIKELY(is.Tell() < length);\n\n    if (!RAPIDJSON_LIKELY(is.Tell() < length))\n        return false;\n\n    const char* p = is.src_;\n    const char* end = is.head_ + length;\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));\n    if (nextAligned > end)\n        return true;\n\n    while (p != nextAligned)\n        if (*p < 0x20 || *p == '\\\"' || *p == '\\\\') {\n            is.src_ = p;\n            return RAPIDJSON_LIKELY(is.Tell() < length);\n        }\n        else\n            os_->PutUnsafe(*p++);\n\n    // The rest of string using SIMD\n    const uint8x16_t s0 = vmovq_n_u8('\"');\n    const uint8x16_t s1 = vmovq_n_u8('\\\\');\n    const uint8x16_t s2 = vmovq_n_u8('\\b');\n    const uint8x16_t s3 = vmovq_n_u8(32);\n\n    for (; p != endAligned; p += 16) {\n        const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));\n        uint8x16_t x = vceqq_u8(s, s0);\n        x = vorrq_u8(x, vceqq_u8(s, s1));\n        x = vorrq_u8(x, vceqq_u8(s, s2));\n        x = vorrq_u8(x, vcltq_u8(s, s3));\n\n        x = vrev64q_u8(x);                     // Rev in 64\n        uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract\n        uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract\n\n        SizeType len = 0;\n        bool escaped = false;\n        if (low == 0) {\n            if (high != 0) {\n                unsigned lz = (unsigned)__builtin_clzll(high);\n                len = 8 + (lz >> 3);\n                escaped = true;\n            }\n        } else {\n            unsigned lz = (unsigned)__builtin_clzll(low);\n            len = lz >> 3;\n            escaped = true;\n        }\n        if (RAPIDJSON_UNLIKELY(escaped)) {   // some of characters is escaped\n            char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));\n            for (size_t i = 0; i < len; i++)\n                q[i] = p[i];\n\n            p += len;\n            break;\n        }\n        vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);\n    }\n\n    is.src_ = p;\n    return RAPIDJSON_LIKELY(is.Tell() < length);\n}\n#endif // RAPIDJSON_NEON\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(_MSC_VER) || defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "src/listen/ClientWorker.cpp",
    "content": "#include <vector>\n#include \"ClientWorker.h\"\n#include \"listen/Listener.h\"\n#include \"src/utils/url.h\"\n#include \"src/utils/GroupKey.h\"\n#include \"src/crypto/md5/md5.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"src/utils/TimeUtils.h\"\n#include \"src/log/Logger.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/http/HttpStatus.h\"\n#include \"src/config/ConfigProxy.h\"\n\n#define MAX(a,b) ((a) > (b) ? (a) : (b))\n\nusing namespace std;\n\nnamespace nacos{\nClientWorker::ClientWorker(ObjectConfigData *objectConfigData) {\n    threadId = 0;\n    stopThread = true;\n    pthread_mutex_init(&watchListMutex, NULL);\n    pthread_mutex_init(&stopThreadMutex, NULL);\n    _objectConfigData = objectConfigData;\n\n    _longPullingTimeoutStr = _objectConfigData->_appConfigManager->get(PropertyKeyConst::CONFIG_LONGPULLLING_TIMEOUT);\n    _longPullingTimeout = atoi(_longPullingTimeoutStr.c_str());\n}\n\nClientWorker::~ClientWorker() {\n    log_debug(\"[ClientWorker]:~ClientWorker()\\n\");\n    stopListening();\n    cleanUp();\n}\n\nNacosString ClientWorker::getServerConfig\n(\n    const NacosString &tenant,\n    const NacosString &dataId,\n    const NacosString &group,\n    long timeoutMs\n) NACOS_THROW(NacosException) {\n    HttpResult res = getServerConfigHelper(tenant, dataId, group, timeoutMs);\n    AppConfigManager *_appConfigManager = _objectConfigData->_appConfigManager;\n    LocalSnapshotManager *localSnapshotManager = _objectConfigData->_localSnapshotManager;\n    switch (res.code) {\n        case HttpStatus::HTTP_OK:\n            localSnapshotManager->saveSnapshot(_appConfigManager->get(PropertyKeyConst::CLIENT_NAME), dataId, group, tenant, res.content);\n            return res.content;\n        case HttpStatus::HTTP_NOT_FOUND:\n            //Update snapshot\n            localSnapshotManager->saveSnapshot(_appConfigManager->get(PropertyKeyConst::CLIENT_NAME), dataId, group, tenant, NULLSTR);\n            throw NacosException(NacosException::HTTP_NOT_FOUND, \"getServerConfig could not get content for Key \" + group + \":\" + dataId);\n        case HttpStatus::HTTP_FORBIDDEN:\n            //Update snapshot\n            localSnapshotManager->saveSnapshot(_appConfigManager->get(PropertyKeyConst::CLIENT_NAME), dataId, group, tenant, NULLSTR);\n            throw NacosException(NacosException::NO_RIGHT, \"permission denied for Key \" + group + \":\" + dataId);\n        default:\n            localSnapshotManager->saveSnapshot(_appConfigManager->get(PropertyKeyConst::CLIENT_NAME), dataId, group, tenant, NULLSTR);\n            throw NacosException(NacosException::SERVER_ERROR, \"getServerConfig failed with code:\" + NacosStringOps::valueOf(res.code));\n    }\n    return NULLSTR;\n}\n\n\nHttpResult ClientWorker::getServerConfigHelper\n(\n    const NacosString &tenant,\n    const NacosString &dataId,\n    const NacosString &group,\n    long timeoutMs\n) NACOS_THROW(NacosException) {\n    std::list <NacosString> headers;\n    std::list <NacosString> paramValues;\n\n    ParamUtils::addKV(paramValues, \"dataId\", dataId);\n\n    if (!isNull(group)) {\n        ParamUtils::addKV(paramValues, \"group\", group);\n    } else {\n        ParamUtils::addKV(paramValues, \"group\", ConfigConstant::DEFAULT_GROUP);\n    }\n\n    if (!isNull(tenant)) {\n        ParamUtils::addKV(paramValues, \"tenant\", tenant);\n    }\n\n    //Get the request url\n    NacosString path = _objectConfigData->_appConfigManager->getContextPath() + ConfigConstant::CONFIG_CONTROLLER_PATH;\n    NacosString serverAddr = _objectConfigData->_serverListManager->getCurrentServerAddr();\n    NacosString url = serverAddr + \"/\" + path;\n    log_debug(\"[ClientWorker]-getServerConfigHelper:httpGet Assembled URL:%s\\n\", url.c_str());\n\n    HttpResult res;\n    ConfigProxy *_configProxy = _objectConfigData->_configProxy;\n    try {\n        res = _configProxy->reqAPI(IHttpCli::GET, url, headers, paramValues, _objectConfigData->encoding, timeoutMs);\n    }\n    catch (NetworkException &e) {\n        throw NacosException(NacosException::SERVER_ERROR, e.what());\n    }\n\n    return res;\n}\n\n\nvoid *ClientWorker::listenerThread(void *parm) {\n    log_debug(\"[ClientWorker]-listenerThread:Entered watch thread...\\n\");\n    ClientWorker *thelistener = (ClientWorker *) parm;\n\n    while (!thelistener->stopThread) {\n        int64_t start_time = TimeUtils::getCurrentTimeInMs();\n        log_debug(\"[ClientWorker]-listenerThread:Start watching at %u...\\n\", start_time);\n        thelistener->performWatch();\n\n        log_debug(\"[ClientWorker]-listenerThread:Watch function exit at %u...\\n\", TimeUtils::getCurrentTimeInMs());\n    }\n\n    return 0;\n}\n\nvector <NacosString> ClientWorker::parseListenedKeys(const NacosString &ReturnedKeys) {\n    NacosString changedKeyList = urldecode(ReturnedKeys);\n\n    vector <NacosString> explodedList;\n    ParamUtils::Explode(explodedList, changedKeyList, ConfigConstant::LINE_SEPARATOR);\n\n    //If the server returns a string with a trailing \\x01, actually there is no data after that\n    //but ParamUtils::Explode will return an extra item with empty string, we need to remove that\n    //from the list so it won't disrupt subsequent operations\n    log_debug(\"[ClientWorker]-parseListenedKeys:extra data:%s\\n\", explodedList[explodedList.size() - 1].c_str());\n    if (explodedList.size() >= 1 && ParamUtils::isBlank(explodedList[explodedList.size() - 1])) {\n        explodedList.pop_back();\n    }\n    return explodedList;\n}\n\nvoid ClientWorker::startListening() {\n    //Already started, skip this\n    if (!stopThread) {\n        log_debug(\"[ClientWorker]-startListening:The thread is already started or the starting is in progress...\\n\");\n        return;\n    }\n\n    pthread_mutex_lock(&stopThreadMutex);\n    if (!stopThread) {\n        pthread_mutex_unlock(&stopThreadMutex);\n        log_debug(\"[ClientWorker]-startListening:The thread is already started or the starting is in progress...\\n\");\n        return;\n    }\n\n    stopThread = false;\n    pthread_mutex_unlock(&stopThreadMutex);\n\n    log_debug(\"[ClientWorker]-startListening:Starting the thread...\\n\");\n    pthread_create(&threadId, NULL, listenerThread, (void *) this);\n    log_debug(\"[ClientWorker]-startListening:Started thread with id:%d...\\n\", threadId);\n}\n\nvoid ClientWorker::stopListening() {\n    log_debug(\"[ClientWorker]-stopListening: entered\\n\");\n    if (stopThread)//Stop in progress\n    {\n        log_debug(\"[ClientWorker]-stopListening:The thread is already stopped or the stop is in progress...\\n\");\n        return;\n    }\n\n    pthread_mutex_lock(&stopThreadMutex);\n    if (stopThread)//Stop in progress\n    {\n        pthread_mutex_unlock(&stopThreadMutex);\n        log_debug(\"[ClientWorker]-stopListening:The thread is already stopped or the stop is in progress...\\n\");\n        return;\n    }\n\n    stopThread = true;\n    pthread_mutex_unlock(&stopThreadMutex);\n\n    pthread_join(threadId, NULL);\n    log_info(\"[ClientWorker]-stopListening:The thread is stopped successfully...\\n\");\n\n}\n\nvoid ClientWorker::addListener\n        (\n                const NacosString &dataId,\n                const NacosString &group,\n                const NacosString &tenant,\n                const NacosString &initialContent,\n                Listener *listener\n        ) {\n    NacosString key = GroupKey::getKeyTenant(dataId, group, tenant);\n    log_debug(\"[ClientWorker]-addListener:Adding listener with key: %s\\n\", key.c_str());\n    pthread_mutex_lock(&watchListMutex);\n\n    //Check whether the listener being added to the list already exists\n    if (listeningKeys.find(key) != listeningKeys.end()) {\n        ListeningData *curListeningData = listeningKeys[key];\n        if (!curListeningData->addListener(listener)) {\n            log_warn(\"[ClientWorker]-addListener:Key %s is already in the watch list, leaving...\\n\", key.c_str());\n        }\n        listener->incRef();\n        pthread_mutex_unlock(&watchListMutex);\n        return;\n    }\n\n    //if the listener does not exist, just create it\n\n    ListeningData *listeningData = new ListeningData(tenant, dataId, group, initialContent);\n\n    //If no, copy one\n    listeningKeys[key] = listeningData;\n    listeningData->addListener(listener);\n    listener->incRef();\n    pthread_mutex_unlock(&watchListMutex);\n    log_debug(\"[ClientWorker]-addListener:Key %s is added successfully!\\n\", key.c_str());\n}\n\n/**\n* Removes a listener from the listened list actively, but slow\n* @param listener the listener to be removed\n* @author Liu, Hanyu\n*/\nvoid ClientWorker::removeListenerActively\n        (\n                const NacosString &dataId,\n                const NacosString &group,\n                const NacosString &tenant,\n                Listener *listener\n        ) {\n    NacosString key = GroupKey::getKeyTenant(dataId, group, tenant);\n    pthread_mutex_lock(&watchListMutex);\n    map<NacosString, ListeningData *>::iterator it = listeningKeys.find(key);\n    //Check whether the cachedata being removed exists\n    if (it == listeningKeys.end()) {\n        log_warn(\"[ClientWorker]-removeListenerActively:Removing a non-existing listener %s, leaving...\\n\", key.c_str());\n        pthread_mutex_unlock(&watchListMutex);\n        return;\n    }\n\n    //If so, remove it and free the resources\n    ListeningData *curListeningData = it->second;\n    bool succRemoved = curListeningData->removeListener(listener);\n    if (!succRemoved) {\n        log_warn(\"[ClientWorker]-removeListenerActively:Removing a non-existing listener %s...\\n\", key.c_str());\n    } else {\n        //remove the listener, it is created by the client but freed by nacos-sdk-cpp\n        log_debug(\"[ClientWorker]-removeListenerActively:Removing a listener %s...\\n\", key.c_str());\n        int refcount = listener->decRef();\n        if (refcount == 0) {\n            log_debug(\"[ClientWorker]-removeListenerActively:\"\n                      \"Refcount of the listener(Name = %s) is 0 so delete it.\\n\", listener->getListenerName().c_str());\n            delete listener;\n            listener = NULL;\n        }\n    }\n\n    //no listener on the list, remove the entry\n    if (curListeningData->isEmpty()) {\n        listeningKeys.erase(key);\n        //free the space for this slot\n        delete curListeningData;\n    }\n    pthread_mutex_unlock(&watchListMutex);\n}\n\n/**\n* Removes a listener from the listened list(very fast compared to removeListenerActively)\n* This function will return fast,\n* since it just mark the remove flag of the listener and wait for the watcher to actually remove it\n* @param listener the listener to be removed\n* @author Liu, Hanyu\n*/\nvoid ClientWorker::removeListener\n        (\n                const NacosString &dataId,\n                const NacosString &group,\n                const NacosString &tenant,\n                Listener *listener\n        ) {\n    //set the remove flag and return quickly\n    //the background process will remove the listener\n    //add this listener to the remove list since it is marked to be removed\n    OperateItem operateItem(dataId, tenant, group, listener);\n    addDeleteItem(operateItem);\n}\n\nNacosString ClientWorker::checkListenedKeys() NACOS_THROW(NetworkException,NacosException) {\n    NacosString postData;\n    pthread_mutex_lock(&watchListMutex);\n    for (map<NacosString, ListeningData *>::iterator it = listeningKeys.begin(); it != listeningKeys.end(); it++) {\n        ListeningData *curListenedKey = it->second;\n\n        postData += curListenedKey->getDataId();\n        postData += ConfigConstant::WORD_SEPARATOR;\n        postData += curListenedKey->getGroup();\n        postData += ConfigConstant::WORD_SEPARATOR;\n\n        if (!isNull(curListenedKey->getTenant())) {\n            postData += curListenedKey->getMD5();\n            postData += ConfigConstant::WORD_SEPARATOR;\n            postData += curListenedKey->getTenant();\n            postData += ConfigConstant::LINE_SEPARATOR;\n        } else {\n            postData += curListenedKey->getMD5();\n            postData += ConfigConstant::LINE_SEPARATOR;\n        }\n    }\n    pthread_mutex_unlock(&watchListMutex);\n\n    list <NacosString> headers;\n    list <NacosString> paramValues;\n\n    headers.push_back(\"Long-Pulling-Timeout\");\n    headers.push_back(_longPullingTimeoutStr);\n\n    paramValues.push_back(ConfigConstant::PROBE_MODIFY_REQUEST);\n    paramValues.push_back(postData);\n    log_debug(\"[ClientWorker]-checkListenedKeys:Assembled postData:%s\\n\", postData.c_str());\n\n    //Get the request url\n    //TODO:move /listener to constant\n    NacosString path = _objectConfigData->_appConfigManager->getContextPath() + ConfigConstant::CONFIG_CONTROLLER_PATH + \"/listener\";\n    HttpResult res;\n\n    NacosString serverAddr = _objectConfigData->_serverListManager->getCurrentServerAddr();\n    NacosString url = serverAddr + \"/\" + path;\n    log_debug(\"[ClientWorker]-checkListenedKeys:httpPost Assembled URL:%s\\n\", url.c_str());\n\n    ConfigProxy *_configProxy = _objectConfigData->_configProxy;\n    res = _configProxy->reqAPI(IHttpCli::POST, url, headers, paramValues, _objectConfigData->encoding, _longPullingTimeout);\n    log_debug(\"[ClientWorker]-checkListenedKeys:Received the message below from server:\\n%s\\n\", res.content.c_str());\n    log_debug(\"[ClientWorker]-checkListenedKeys:return status:httpcode=%d curlcode=%d\\n\", res.code, res.curlcode);\n    \n    if (res.code != HttpStatus::HTTP_OK) {\n        //bugfix #52 please check github\n        throw NacosException(res.code, \"Error while watching keys\");\n    }\n\n    return res.content;\n}\n\nvoid ClientWorker::performWatch() {\n    MD5 md5;\n    NacosString changedData;\n    try {\n        changedData = checkListenedKeys();\n    } catch (NetworkException &e) {\n        log_warn(\"[ClientWorker]-performWatch:sleep and retry, reason: NetworkException with: %s\\n\", e.what());\n        //wait for at lease 3 secs to avoid too many wake-ups when the network is down\n        sleep(MAX(_longPullingTimeout / 10000, 3));\n        return;\n    } catch (NacosException &e) {\n        log_warn(\"[ClientWorker]-performWatch:sleep and retry, reason: NacosException with: %s\\n\", e.what());\n        //same reason as above\n        sleep(MAX(_longPullingTimeout / 10000, 3));\n        return;\n    }\n\n    vector <NacosString> changedList = ClientWorker::parseListenedKeys(changedData);\n    pthread_mutex_lock(&watchListMutex);\n    for (std::vector<NacosString>::iterator it = changedList.begin(); it != changedList.end(); it++) {\n        NacosString dataId, group, tenant;\n        ParamUtils::parseString2KeyGroupTenant(*it, dataId, group, tenant);\n        log_debug(\"[ClientWorker]-performWatch:Processing item:%s, dataId = %s, group = %s, tenant = %s\\n\",\n                  it->c_str(), dataId.c_str(), group.c_str(), tenant.c_str());\n\n        NacosString key = GroupKey::getKeyTenant(dataId, group, tenant);\n        map<NacosString, ListeningData *>::iterator listenedDataIter = listeningKeys.find(key);\n        HttpResult res;\n        //check whether the data being watched still exists\n        if (listenedDataIter != listeningKeys.end()) {\n            log_debug(\"[ClientWorker]-performWatch:Found entry for:%s\\n\", key.c_str());\n            ListeningData *listenedList = listenedDataIter->second;\n            NacosString updatedcontent = \"\";\n\n            try {\n                res = getServerConfigHelper(listenedList->getTenant(), listenedList->getDataId(),\n                                                 listenedList->getGroup(),\n                                                 _objectConfigData->_appConfigManager->getServeReqTimeout());\n                updatedcontent = res.content;\n            }\n            catch (NacosException &e) {\n                //Same design as SubscriptionPoller\n                log_warn(\"[ClientWorker]-performWatch:Encountered exception when getting config from server:%s:%s:%s\\n\",\n                         listenedList->getTenant().c_str(),\n                         listenedList->getGroup().c_str(),\n                         listenedList->getDataId().c_str());\n                //wait for at lease 3 secs to avoid too many wake-ups when the network is down\n                sleep(MAX(_longPullingTimeout / 10000, 3));\n                break;\n            }\n            log_debug(\"[ClientWorker]-performWatch:Data fetched from the server: %s\\n\", updatedcontent.c_str());\n\n            //Bugfix #42, please check github\n            if (res.code == HttpStatus::HTTP_OK) {\n                md5.reset();\n                md5.update(updatedcontent.c_str());\n                listenedList->setMD5(md5.toString());\n                log_debug(\"[ClientWorker]-performWatch:MD5 got for that data: %s\\n\", listenedList->getMD5().c_str());\n            } else {\n                listenedList->setMD5(\"\");\n                updatedcontent = \"\";\n\n            }\n            std::map < Listener * , char > const *listenerList = listenedList->getListenerList();\n            for (std::map<Listener *, char>::const_iterator listenerIt = listenerList->begin();\n                 listenerIt != listenerList->end(); listenerIt++) {\n                Listener *curListener = listenerIt->first;\n\n                NACOS_ASSERT(curListener->refCnt() > 0);\n                curListener->receiveConfigInfo(updatedcontent);\n            }\n        }\n    }\n    clearDeleteList(20);//TODO:constant\n    pthread_mutex_unlock(&watchListMutex);\n}\n\n/**\n* Removes listeners in deleteList\n*\n* *NOT THREAD SAFE*, must be called within a watchListMutex guarded area or after the watcher thread is stopped\n* @param maxRemoves if < 0, clear all items in the deleteList\n* @author Liu, Hanyu\n*/\nvoid ClientWorker::clearDeleteList(int maxRemoves) {\n    int removeCount = 0;\n    while (!deleteList.empty()) {\n        //remove limited items every time\n        if (maxRemoves > 0 && removeCount >= maxRemoves) {\n            break;\n        }\n        std::list<OperateItem>::iterator it = deleteList.begin();\n        OperateItem itm = *it;\n        NacosString key = GroupKey::getKeyTenant(itm.getDataId(), itm.getGroup(), itm.getTenant());\n\n        if (listeningKeys.find(key) == listeningKeys.end()) {\n            log_warn(\"[ClientWorker]-clearDeleteList:Trying to remove non-existent key: %s\\n\", key.c_str());\n            deleteList.erase(it);\n            continue;\n        }\n\n        ListeningData *slotOfListener = listeningKeys[key];\n\n        Listener *theListener = itm.getListener();\n        slotOfListener->removeListener(theListener);\n        int refcount = theListener->decRef();\n        log_debug(\"[ClientWorker]-clearDeleteList:The listener (Name = %s) on deleteList is removed, key = %s.\\n\",\n                  theListener->getListenerName().c_str(), key.c_str());\n        if (refcount == 0) {\n            delete theListener;\n        }\n        itm.setListener(NULL);\n        if (slotOfListener->isEmpty()) {\n            log_debug(\"[ClientWorker]-clearDeleteList:The slot (Name = %s) is empty and removed\\n\", key.c_str());\n            delete slotOfListener;\n            slotOfListener = NULL;\n            listeningKeys.erase(key);\n        }\n        deleteList.erase(it);\n        removeCount++;\n    }\n}\n\nvoid ClientWorker::cleanUp() {\n    log_debug(\"[ClientWorker]-cleanUp:entered\\n\");\n    clearDeleteList(0);\n    for (map<NacosString, ListeningData *>::iterator it = listeningKeys.begin(); it != listeningKeys.end(); it++) {\n        ListeningData *listeningData = it->second;\n        log_debug(\"[ClientWorker]-cleanUp:Cleaning %s\\n\", listeningData->toString().c_str());\n        listeningData->clearListeners();\n        delete listeningData;\n        listeningData = NULL;\n    }\n}\n\nvoid ClientWorker::addDeleteItem(const OperateItem &operateItem) {\n    log_debug(\"[ClientWorker]-addDeleteItem:Adding delete item: %s\\n\", operateItem.toString().c_str());\n    pthread_mutex_lock(&watchListMutex);\n    deleteList.push_back(operateItem);\n    pthread_mutex_unlock(&watchListMutex);\n}\n}//namespace nacos"
  },
  {
    "path": "src/listen/ClientWorker.h",
    "content": "#ifndef __CLIENT_WORKER_H_\n#define __CLIENT_WORKER_H_\n\n#include <map>\n#include <vector>\n#include <pthread.h>\n#include \"NacosString.h\"\n#include \"listen/Listener.h\"\n#include \"ListeningData.h\"\n#include \"OperateItem.h\"\n#include \"src/config/AppConfigManager.h\"\n#include \"src/server/ServerListManager.h\"\n#include \"src/config/LocalSnapshotManager.h\"\n#include \"NacosExceptions.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\n/**\n * ClientWorker\n *\n * @author Liu, Hanyu\n * Directly migrated from Java, but with significant work of rewrite/redesign\n */\nnamespace nacos{\nclass ClientWorker {\nprivate:\n    //This list holds the listeners to be removed after a performWatch() event\n    //And after all the items in this list is removed, an extra check must be performed on listeningKeys\n    //to make sure if the entry of that key is empty, remove the entry\n    std::list <OperateItem> deleteList;\n    //dataID||group||tenant -> Cachedata* Mapping\n    std::map<NacosString, ListeningData *> listeningKeys;\n    pthread_mutex_t watchListMutex;//TODO:refactor to Mutex\n    ObjectConfigData *_objectConfigData;\n    //Listener thread related info\n    pthread_t threadId;\n\n    volatile bool stopThread;\n    pthread_mutex_t stopThreadMutex;\n\n    int _longPullingTimeout;\n    NacosString _longPullingTimeoutStr;\n\n    static void *listenerThread(void *watcher);\n\n    //You just can't construct a ClientWorker object without any parameter\n    ClientWorker();\n\n    std::vector <NacosString> parseListenedKeys(const NacosString &ReturnedKeys);\n\n    NacosString checkListenedKeys() NACOS_THROW(NetworkException,NacosException);\n\n    void clearDeleteList(int maxRemoves);\n\n    void cleanUp();\n\n    void addDeleteItem(const OperateItem &item);\n\npublic:\n    ClientWorker(ObjectConfigData *objectConfigData);\n\n    ~ClientWorker();\n\n    void startListening();\n\n    void stopListening();\n\n    void addListener(const NacosString &dataId,\n                     const NacosString &group,\n                     const NacosString &tenant,\n                     const NacosString &initialContent,\n                     Listener *listener);\n\n    void removeListenerActively(const NacosString &dataId,\n                                const NacosString &group,\n                                const NacosString &tenant,\n                                Listener *listener);\n\n    void removeListener(const NacosString &dataId,\n                        const NacosString &group,\n                        const NacosString &tenant,\n                        Listener *listener);\n\n    void performWatch();\n\n    NacosString getServerConfig(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                                long timeoutMs) NACOS_THROW(NacosException);\n    HttpResult getServerConfigHelper(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                                long timeoutMs) NACOS_THROW(NacosException);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/listen/ListeningData.h",
    "content": "#ifndef __LISTENINGDATA_H_\n#define __LISTENINGDATA_H_\n\n#include <map>\n#include <list>\n#include \"NacosString.h\"\n#include \"listen/Listener.h\"\n#include \"src/crypto//md5/md5.h\"\n#include \"src/log/Logger.h\"\n\nnamespace nacos{\nclass ListeningData {\nprivate:\n    NacosString tenant;\n    NacosString dataId;\n    NacosString group;\n    NacosString dataMD5;\n    std::map<Listener *, char> listenerList;\npublic:\n    NacosString toString() const {\n        return tenant + \":\" + dataId + \":\" + group + \":\" + dataMD5 + \", listenerList size=\" +\n               NacosStringOps::valueOf(listenerList.size());\n    }\n\n    NacosString getDataId() const {\n        return dataId;\n    }\n\n    NacosString getTenant() const {\n        return tenant;\n    }\n\n    NacosString getGroup() const {\n        return group;\n    }\n\n    NacosString getMD5() const {\n        return dataMD5;\n    }\n\n    void setMD5(const NacosString &md5) {\n        dataMD5 = md5;\n    }\n\n    /**\n    * Adds a listener to this object being listened for further notification\n    * @param listener the listener to be added\n    * @return true if added successfully\n    *         false if the listener is already in the list\n    */\n    bool addListener(Listener *listener) {\n        if (listenerList.find(listener) != listenerList.end()) {\n            return false;\n        }\n\n        listenerList[listener] = 1;\n        return true;\n    }\n\n    /**\n    * Removes a listener from this object being listened\n    * @param listener the listener to be removed\n    * @return true if removed successfully\n    *         false if the listener does not exist in the list\n    */\n    bool removeListener(Listener *listener) {\n        if (listenerList.count(listener) <= 0) {\n            return false;\n        }\n\n        listenerList.erase(listener);\n        return true;\n    }\n\n    void clearListeners() {\n        while (!listenerList.empty()) {\n            std::map<Listener *, char>::iterator it = listenerList.begin();\n            Listener *theListener = it->first;\n            int ref = theListener->decRef();\n            log_debug(\"ListeningData::clearListeners():Removing %s, refcnt = %d\\n\",\n                      theListener->getListenerName().c_str(), theListener->refCnt());\n            if (ref == 0) {\n                delete theListener;\n            }\n            listenerList.erase(it);\n        }\n    }\n\n    bool isEmpty() const {\n        return listenerList.size() == 0;\n    }\n\n    ListeningData(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                  const NacosString &cfgcontent) {\n        setContent(tenant, dataId, group, cfgcontent);\n    }\n\n    void setContent(const NacosString &tenant, const NacosString &dataId, const NacosString &group,\n                    const NacosString &cfgcontent) {\n        this->tenant = tenant;\n        this->dataId = dataId;\n        this->group = group;\n        if (!isNull(cfgcontent)) {\n            MD5 md5;//TODO:optimize this to a static object to avoid repeatedly ctor&dtor of object\n            md5.update(cfgcontent);\n            this->dataMD5 = md5.toString();\n        } else {\n            this->dataMD5 = \"\";\n        }\n    }\n\n    bool operator==(const ListeningData &rhs) const {\n        return tenant == rhs.tenant && dataId == rhs.dataId && group == rhs.group;\n    };\n\n    const std::map<Listener *, char> *getListenerList() const {\n        return &this->listenerList;\n    }\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/listen/OperateItem.h",
    "content": "#ifndef __OPERATE_ITM_H_\n#define __OPERATE_ITM_H_\n\n#include \"NacosString.h\"\n#include \"listen/Listener.h\"\n\n/**\n * ListeningData\n *\n * @author Liu, Hanyu\n * Keeps track of the items to be operated on\n */\nnamespace nacos{\nclass OperateItem {\nprivate:\n    NacosString tenant;\n    NacosString dataId;\n    NacosString group;\n    Listener *listener;\npublic:\n    NacosString getDataId() const {\n        return dataId;\n    }\n\n    NacosString getTenant() const {\n        return tenant;\n    }\n\n    NacosString getGroup() const {\n        return group;\n    }\n\n    Listener *getListener() const {\n        return listener;\n    }\n\n    void setListener(Listener *listener) {\n        this->listener = listener;\n    }\n\n    OperateItem(const NacosString &dataId,\n                const NacosString &tenant,\n                const NacosString &group,\n                Listener *listener) {\n        this->dataId = dataId;\n        this->tenant = tenant;\n        this->group = group;\n        this->listener = listener;\n    }\n\n    NacosString toString() const {\n        return tenant + \":\" + group + \":\" + dataId;\n    }\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/log/Logger.cpp",
    "content": "#include <stdio.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <stdlib.h>\n#include \"Logger.h\"\n#include \"src/utils/TimeUtils.h\"\n#include \"NacosExceptions.h\"\n#include \"src/utils/ConfigParserUtils.h\"\n#include \"Properties.h\"\n#include \"src/utils/DirUtils.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"src/config/IOUtils.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include <ctime>\n#include <sys/stat.h>\n\nnamespace nacos{\n\nLOG_LEVEL Logger::_CUR_SYS_LOG_LEVEL = ERROR;\nNacosString Logger::_log_base_dir = \"\";\nNacosString Logger::_log_file = \"\";\nint64_t Logger::_rotate_size;\nint64_t Logger::_last_rotate_time;\nFILE *Logger::_output_file;\nMutex Logger::setFileLock;\n\n//rotate time (in Ms)\nvoid Logger::setRotateSize(int64_t rotateSize) {\n    _rotate_size = rotateSize;\n}\n\nvoid Logger::setBaseDir(const NacosString &baseDir) {\n    LockGuard _setFile(setFileLock);\n    _log_base_dir = baseDir;\n    if (_output_file != NULL) {\n        fclose(_output_file);\n        _output_file = NULL;\n    }\n\n    _log_file = _log_base_dir + ConfigConstant::FILE_SEPARATOR + \"nacos-sdk-cpp.log\";\n    IOUtils::recursivelyCreate(_log_base_dir.c_str());\n    _output_file = fopen(_log_file.c_str(), \"a\");\n    if (_output_file == NULL) {\n        NacosString errMsg = \"Unable to open file \";\n        errMsg += _log_file;\n        throw NacosException(NacosException::UNABLE_TO_OPEN_FILE, errMsg);\n    }\n}\n\nvoid Logger::setLogLevel(LOG_LEVEL level) {\n    _CUR_SYS_LOG_LEVEL = level;\n};\n\nint64_t Logger::getRotateSize() {\n    return _rotate_size;\n}\n\nconst NacosString &Logger::getBaseDir() {\n    return _log_base_dir;\n}\n\nLOG_LEVEL Logger::getLogLevel() {\n    return _CUR_SYS_LOG_LEVEL;\n}\n\nint Logger::debug_helper(LOG_LEVEL level, const char *format, va_list args) {\n    //Since the current system debug level is greater than this message\n    //Supress it\n    if (Logger::_CUR_SYS_LOG_LEVEL > level) {\n        return 0;\n    }\n    //va_list argList;\n\n    //va_start(argList, format);\n    int64_t now = TimeUtils::getCurrentTimeInMs();\n\n    struct stat stat_buf;\n    stat(_log_file.c_str(), &stat_buf);\n    if (stat_buf.st_size >= _rotate_size) {\n        truncate(_log_file.c_str(), 0);\n        _last_rotate_time = now;\n    }\n\n    const char *log_level;\n    switch (level) {\n        case DEBUG:\n            log_level = \"[DEBUG]\";\n            break;\n        case INFO:\n            log_level = \"[INFO]\";\n            break;\n        case WARN:\n            log_level = \"[WARN]\";\n            break;\n        case ERROR:\n            log_level = \"[ERROR]\";\n            break;\n        case NONE:\n            log_level = \"[NONE]\";\n            break;\n        default:\n            log_level = \"[UNKNOWN]\";\n            break;\n    }\n\n    time_t t = time(0);\n    struct tm current_time;\n    localtime_r(&t, &current_time);\n    //length of [9999-12-31 99:99:99] = 19\n    char time_buf[22];\n    strftime(time_buf, sizeof(time_buf), \"[%Y-%m-%d %H:%M:%S]\", &current_time);\n\n    int retval = fprintf(_output_file, \"%s%s\", time_buf, log_level);\n    retval += vfprintf(_output_file, format, args);\n    fflush(_output_file);\n    //va_end(argList);\n    return retval;\n}\n\n//Output string in self-defined log_level\nint Logger::debug_print(LOG_LEVEL level, const char *format, ...) {\n    va_list argList;\n\n    va_start(argList, format);\n    int retval = debug_helper(level, format, argList);\n    va_end(argList);\n    return retval;\n}\n\nint Logger::debug_debug(const char *format, ...) {\n    va_list argList;\n\n    va_start(argList, format);\n    int retval = debug_helper(DEBUG, format, argList);\n    va_end(argList);\n    return retval;\n}\n\nint Logger::debug_info(const char *format, ...) {\n    va_list argList;\n\n    va_start(argList, format);\n    int retval = debug_helper(INFO, format, argList);\n    va_end(argList);\n    return retval;\n}\n\nint Logger::debug_warn(const char *format, ...) {\n    va_list argList;\n\n    va_start(argList, format);\n    int retval = debug_helper(WARN, format, argList);\n    va_end(argList);\n    return retval;\n}\n\nint Logger::debug_error(const char *format, ...) {\n    va_list argList;\n\n    va_start(argList, format);\n    int retval = debug_helper(ERROR, format, argList);\n    va_end(argList);\n    return retval;\n}\n\nvoid Logger::deInit() {\n    if (_output_file != NULL) {\n        fclose(_output_file);\n        _output_file = NULL;\n    }\n}\n\nvoid Logger::initializeLogSystem() {\n    Properties props;\n\n    try {\n        props = ConfigParserUtils::parseConfigFile(DirUtils::getCwd() + ConfigConstant::FILE_SEPARATOR + ConfigConstant::DEFAULT_CONFIG_FILE);\n    } catch (IOException &e) {\n        //if we failed to read log settings\n        //use default settings as backup\n    }\n\n    applyLogSettings(props);\n}\n\n\nvoid Logger::applyLogSettings(Properties &props) {\n    if (!props.contains(PropertyKeyConst::LOG_PATH)) {\n        NacosString homedir = DirUtils::getHome();\n        Logger::setBaseDir(homedir + ConfigConstant::FILE_SEPARATOR + \"nacos\" + ConfigConstant::FILE_SEPARATOR + \"logs\");\n    } else {\n        Logger::setBaseDir(props[PropertyKeyConst::LOG_PATH]);\n    }\n\n    if (props.contains(PropertyKeyConst::LOG_LEVEL)) {\n        //default log level is error, if user specifies it within configuration file, update it\n        NacosString &logLevelStr = props[PropertyKeyConst::LOG_LEVEL];\n\n        if (logLevelStr == \"DEBUG\") {\n            Logger::setLogLevel(DEBUG);\n        } else if (logLevelStr == \"INFO\") {\n            Logger::setLogLevel(INFO);\n        } else if (logLevelStr == \"WARN\") {\n            Logger::setLogLevel(WARN);\n        } else if (logLevelStr == \"ERROR\") {\n            Logger::setLogLevel(ERROR);\n        } else if (logLevelStr == \"NONE\") {\n            Logger::setLogLevel(NONE);\n        } else {\n            throw NacosException(NacosException::INVALID_CONFIG_PARAM, \"Invalid option \" + logLevelStr + \" for \" + PropertyKeyConst::LOG_LEVEL);\n        }\n    }\n\n    if (!props.contains(PropertyKeyConst::LOG_ROTATE_SIZE)) {\n        Logger::setRotateSize(10 * 1024 *1024);//10M by default\n    } else {\n        const NacosString &logRotateSizeStr = props[PropertyKeyConst::LOG_ROTATE_SIZE];\n        if (ParamUtils::isBlank(logRotateSizeStr)) {\n            throw NacosException(NacosException::INVALID_CONFIG_PARAM,\n                                 \"Invalid option '\" + logRotateSizeStr + \"' for \" + PropertyKeyConst::LOG_ROTATE_SIZE);\n        }\n\n        size_t logrotate_lastch = logRotateSizeStr.length() - 1;\n        int mulplier = 1;\n        unsigned long logRotateSize = 0;\n        switch (logRotateSizeStr[logrotate_lastch])\n        {\n            case 'g':\n            case 'G':\n                mulplier *= 1024;\n            case 'm':\n            case 'M':\n                mulplier *= 1024;\n            case 'k':\n            case 'K':\n                mulplier *= 1024;\n                logRotateSize = atol(logRotateSizeStr.substr(0, logrotate_lastch).c_str());//logrotate_lastch = exclude the unit\n                logRotateSize *= mulplier;\n                break;\n            default:\n                if (!isdigit(logRotateSizeStr[logrotate_lastch])) {\n                    throw NacosException(NacosException::INVALID_CONFIG_PARAM,\n                        \"Invalid option '\" + logRotateSizeStr + \"' for \" + PropertyKeyConst::LOG_ROTATE_SIZE + \", the unit of size must be G/g M/m K/k or decimal numbers.\");\n\n                }\n                mulplier = 1;\n                logRotateSize = atol(logRotateSizeStr.substr(0, logRotateSizeStr.length()).c_str());\n                break;\n        }\n\n        if (logRotateSize <= 0) {\n            throw NacosException(NacosException::INVALID_CONFIG_PARAM,\n                                 PropertyKeyConst::LOG_ROTATE_SIZE + \" should be greater than 0\");\n        }\n        Logger::setRotateSize(logRotateSize);\n    }\n\n    log_info(\"Current log path:%s\\n\", Logger::getBaseDir().c_str());\n}\n\nvoid Logger::Init() {\n    initializeLogSystem();\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/log/Logger.h",
    "content": "#ifndef __LOGGER_H_\n#define __LOGGER_H_\n\n#include <cstdarg>\n#include <stdint.h>\n#include \"NacosString.h\"\n#include \"src/thread/Mutex.h\"\n#include \"Properties.h\"\n\n#define DETAILED_DEBUG_INFO\n\n//TODO:Line info\n#ifndef DETAILED_DEBUG_INFO\n#define log_print(level, format, args...) Logger::debug_print(level, format, ##args)\n#define log_debug(format, args...) Logger::debug_debug(format, ##args)\n#define log_info(format, args...) Logger::debug_info(format, ##args)\n#define log_warn(format, args...) Logger::debug_warn(format, ##args)\n#define log_error(format, args...) Logger::debug_error(format, ##args)\n#else\n#define STR(X) #X\n#define log_print(level, format, args...) Logger::debug_print(level, format, ##args)\n#define log_debug(format, args...) Logger::debug_debug(format, ##args)\n#define log_info(format, args...) Logger::debug_info(format, ##args)\n#define log_warn(format, args...) Logger::debug_warn(format, ##args)\n#define log_error(format, args...) Logger::debug_error(format, ##args)\n#endif\n\nnamespace nacos{\n\nenum LOG_LEVEL {\n    DEBUG = 0,\n    INFO,\n    WARN,\n    ERROR,\n    NONE\n};\n\n/**\n * Logger\n * Author: Liu, Hanyu\n * This piece of code is a little bit weird, I have to admit\n * Actually there are 2 stages which need logging:\n * 1. The nacos-client is up but no client service is created, need to log issues when creating client service object\n * 2. client service is created, now need to log issue for the client service\n *\n * stage #1 is called the bootstrap stage\n * stage #2 is called the runtime stage\n *\n * On stage #1, the log will be written to:\n * homedir(~)/nacos/logs/nacos-sdk-cpp.log\n *\n * On stage #2, the path can be configured AT MOST ONCE\n * The path will be implicitly configured when the first client service object is created, so if you don't specify it, the default setting(same as #1) will be used\n */\nclass Logger {\nprivate:\n    static LOG_LEVEL _CUR_SYS_LOG_LEVEL;\n    static NacosString _log_base_dir;\n    static NacosString _log_file;\n    static int64_t _rotate_size;\n    static int64_t _last_rotate_time;\n    static FILE *_output_file;\n\n    static Mutex setFileLock;\n\n    static int debug_helper(LOG_LEVEL level, const char *format, va_list args);\n\n    static void initializeLogSystem();\n\npublic:\n\n    static void applyLogSettings(Properties &props);\n    static void setRotateSize(int64_t rotateSize);\n    static void setBaseDir(const NacosString &baseDir);\n    static void setLogLevel(LOG_LEVEL level);\n\n    static int64_t getRotateSize();\n    static const NacosString &getBaseDir();\n    static LOG_LEVEL getLogLevel();\n\n    //Output string in self-defined log_level\n    static int debug_print(LOG_LEVEL level, const char *format, ...);\n\n    static int debug_debug(const char *format, ...);\n\n    static int debug_info(const char *format, ...);\n\n    static int debug_warn(const char *format, ...);\n\n    static int debug_error(const char *format, ...);\n\n    static void Init();\n    static void deInit();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/naming/Cluster.cpp",
    "content": "#include \"naming/Cluster.h\"\n\nnamespace nacos{\n\nNacosString Cluster::getName() const {\n    return name;\n}\n\nvoid Cluster::setName(const NacosString &name) {\n    Cluster::name = name;\n}\n\nHealthChecker Cluster::getHealthChecker() const {\n    return healthChecker;\n}\n\nvoid Cluster::setHealthChecker(const HealthChecker &healthChecker) {\n    Cluster::healthChecker = healthChecker;\n}\n\nstd::map<NacosString, NacosString> Cluster::getMetadata() const {\n    return metadata;\n}\n\nvoid Cluster::setMetadata(const std::map<NacosString, NacosString> &metadata) {\n    Cluster::metadata = metadata;\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/naming/Instance.cpp",
    "content": "#include \"naming/Instance.h\"\r\n#include \"src/utils/ParamUtils.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\nnamespace nacos{\r\nInstance::Instance() {\r\n    weight = (double)1;\r\n    healthy = true;\r\n    enabled = true;\r\n    ephemeral = true;\r\n    instanceId = \"\";\r\n    ip = \"\";\r\n    clusterName = \"\";\r\n    serviceName = \"\";\r\n    port = 0;\r\n}\r\n\r\nNacosString Instance::toString() const{\r\n    return \"instanceId:\" + instanceId + \" ip:\" + ip + \" port:\" + NacosStringOps::valueOf(port) +\r\n           \" weight:\" + NacosStringOps::valueOf(weight) + \" healthy:\" + NacosStringOps::valueOf(healthy) +\r\n           \" enabled:\" + NacosStringOps::valueOf(enabled) + \" ephemeral:\" + NacosStringOps::valueOf(ephemeral) +\r\n           \" clusterName:\" + clusterName + \" serviceName:\" + serviceName + \" metadata:{\" +\r\n           ParamUtils::Implode(metadata) + \"}\";\r\n}\r\n\r\nNacosString Instance::toInetAddr() {\r\n    return  ip + \":\" + NacosStringOps::valueOf(port);\r\n}\r\n\r\nInstance & Instance::operator = (const Instance &rhs)\r\n{\r\n    this->instanceId = rhs.instanceId;\r\n    this->ip = rhs.ip;\r\n    this->port = rhs.port;\r\n    this->weight = rhs.weight;\r\n    this->healthy = rhs.healthy;\r\n    this->enabled = rhs.enabled;\r\n    this->ephemeral = rhs.ephemeral;\r\n    this->clusterName = rhs.clusterName;\r\n    this->metadata = rhs.metadata;\r\n    return *this;\r\n}\r\n\r\nbool Instance::operator != (const Instance &rhs) const\r\n{\r\n    return !operator==(rhs);\r\n}\r\nbool Instance::operator == (const Instance &rhs) const\r\n{\r\n    return\r\n    this->instanceId == rhs.instanceId &&\r\n    this->ip == rhs.ip &&\r\n    this->port == rhs.port &&\r\n    this->weight == rhs.weight &&\r\n    this->healthy == rhs.healthy &&\r\n    this->enabled == rhs.enabled &&\r\n    this->ephemeral == rhs.ephemeral &&\r\n    this->clusterName == rhs.clusterName &&\r\n    this->metadata == rhs.metadata;\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/naming/NacosNamingMaintainService.cpp",
    "content": "#include \"src/naming/NacosNamingMaintainService.h\"\n#include \"src/security/SecurityManager.h\"\n#include \"constant/ConfigConstant.h\"\n\nusing namespace std;\n\nnamespace nacos{\n\nNacosNamingMaintainService::NacosNamingMaintainService(ObjectConfigData *objectConfigData) {\n    _objectConfigData = objectConfigData;\n    if (_objectConfigData->_appConfigManager->nacosAuthEnabled()) {\n        _objectConfigData->_securityManager->login();\n        _objectConfigData->_securityManager->start();\n    }\n}\n\nbool NacosNamingMaintainService::updateInstance\n(\n    const NacosString &serviceName,\n    const NacosString & groupName,\n    const Instance &instance\n) NACOS_THROW(NacosException) {\n    Instance paramInstance = instance;\n    paramInstance.serviceName = serviceName;\n    paramInstance.groupName = groupName;\n    return _objectConfigData->_serverProxy->updateServiceInstance(paramInstance);\n}\n\nServiceInfo2 NacosNamingMaintainService::queryService\n(\n    const NacosString &serviceName,\n    const NacosString &groupName\n) NACOS_THROW(NacosException) {\n    return _objectConfigData->_serverProxy->getServiceInfo(serviceName, groupName);\n}\n\nbool NacosNamingMaintainService::createService(const ServiceInfo2 &service, naming::Selector *selector) NACOS_THROW(NacosException) {\n    ServiceInfo2 parmServiceInfo = service;\n    if (!parmServiceInfo.isGroupNameSet()) {\n        parmServiceInfo.setGroupName(ConfigConstant::DEFAULT_GROUP);\n    }\n    return _objectConfigData->_serverProxy->createServiceInfo(parmServiceInfo, selector);\n}\n\nbool NacosNamingMaintainService::deleteService(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException) {\n    return _objectConfigData->_serverProxy->deleteServiceInfo(serviceName, groupName);\n}\n\nbool NacosNamingMaintainService::updateService(const ServiceInfo2 &service, naming::Selector *selector) NACOS_THROW(NacosException) {\n    return _objectConfigData->_serverProxy->updateServiceInfo(service, selector);\n}\n\nNacosNamingMaintainService::~NacosNamingMaintainService() {\n    delete _objectConfigData;\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/naming/NacosNamingMaintainService.h",
    "content": "#ifndef __NACOS_NAM_MTN_SVC_H_\n#define __NACOS_NAM_MTN_SVC_H_\n\n#include \"naming/NamingMaintainService.h\"\n#include \"naming/Instance.h\"\n#include \"src/naming/NamingProxy.h\"\n#include \"src/http/IHttpCli.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\n\n/**\n * NacosNamingMaintainService\n * Maintain functions for Nacos\n *\n * @author liaochuntao\n * @author Liu, Hanyu\n * Maintain service\n * Special thanks to @liaochuntao\n */\nclass NacosNamingMaintainService : public NamingMaintainService {\nprivate:\n    NacosNamingMaintainService();\n    ObjectConfigData *_objectConfigData;\npublic:\n    NacosNamingMaintainService(ObjectConfigData *objectConfigData);\n    bool updateInstance(const NacosString &serviceName, const NacosString & groupName, const Instance &instance) NACOS_THROW(NacosException);\n    ServiceInfo2 queryService(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException);\n    bool createService(const ServiceInfo2 &service, naming::Selector *selector) NACOS_THROW(NacosException);\n    bool deleteService(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException);\n    bool updateService(const ServiceInfo2 &service, naming::Selector *selector) NACOS_THROW(NacosException);\n    virtual ~NacosNamingMaintainService();\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/naming/NacosNamingService.cpp",
    "content": "#include \"src/naming/NacosNamingService.h\"\r\n#include \"src/naming/subscribe/SubscriptionPoller.h\"\r\n#include \"src/naming/subscribe/UdpNamingServiceListener.h\"\r\n#include \"src/naming/beat/BeatReactor.h\"\r\n#include \"src/utils/SequenceProvider.h\"\r\n#include \"src/utils/NamingUtils.h\"\r\n#include \"constant/UtilAndComs.h\"\r\n#include \"src/utils/ParamUtils.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n#include \"src/json/JSON.h\"\r\n\r\nusing namespace std;\r\nusing nacos::naming::selectors::Selector;\r\n\r\nnamespace nacos{\r\nNacosNamingService::NacosNamingService(ObjectConfigData *objectConfigData) {\r\n    _objectConfigData = objectConfigData;\r\n    _objectConfigData->_beatReactor->start();\r\n    _objectConfigData->_subscriptionPoller->start();\r\n    _objectConfigData->_udpNamingServiceListener->start();\r\n\r\n    if (_objectConfigData->_appConfigManager->nacosAuthEnabled()) {\r\n        _objectConfigData->_securityManager->login();\r\n        _objectConfigData->_securityManager->start();\r\n    }\r\n}\r\n\r\nNacosNamingService::~NacosNamingService() {\r\n    delete _objectConfigData;\r\n}\r\n\r\nvoid NacosNamingService::registerInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &ip,\r\n                int port\r\n        ) NACOS_THROW(NacosException) {\r\n    registerInstance(serviceName, ip, port, ConfigConstant::DEFAULT_CLUSTER_NAME);\r\n}\r\n\r\nvoid NacosNamingService::registerInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                const NacosString &ip,\r\n                int port\r\n        ) NACOS_THROW(NacosException) {\r\n    registerInstance(serviceName, groupName, ip, port, ConfigConstant::DEFAULT_CLUSTER_NAME);\r\n}\r\n\r\nvoid NacosNamingService::registerInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &ip,\r\n                int port,\r\n                const NacosString &clusterName\r\n        ) NACOS_THROW(NacosException) {\r\n    registerInstance(serviceName, ConfigConstant::DEFAULT_GROUP, ip, port, clusterName);\r\n}\r\n\r\nvoid NacosNamingService::registerInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                const NacosString &ip,\r\n                int port,\r\n                const NacosString &clusterName\r\n        ) NACOS_THROW(NacosException) {\r\n    Instance instance;\r\n    instance.ip = ip;\r\n    instance.port = port;\r\n    instance.weight = (double)1;\r\n    instance.clusterName = clusterName;\r\n\r\n    registerInstance(serviceName, groupName, instance);\r\n}\r\n\r\nvoid NacosNamingService::registerInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                Instance &instance\r\n        ) NACOS_THROW(NacosException) {\r\n    registerInstance(serviceName, ConfigConstant::DEFAULT_GROUP, instance);\r\n}\r\n\r\nvoid NacosNamingService::registerInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                Instance &instance\r\n        ) NACOS_THROW(NacosException) {\r\n    const NacosString &instanceIdPrefix = _objectConfigData->_appConfigManager->get(PropertyKeyConst::INSTANCE_ID_PREFIX);\r\n    instance.instanceId = instanceIdPrefix + NacosStringOps::valueOf(_objectConfigData->_sequenceProvider->next());\r\n    if (instance.ephemeral) {\r\n        BeatInfo beatInfo;\r\n        beatInfo.serviceName = NamingUtils::getGroupedName(serviceName, groupName);\r\n        beatInfo.ip = instance.ip;\r\n        beatInfo.port = instance.port;\r\n        beatInfo.cluster = instance.clusterName;\r\n        beatInfo.weight = instance.weight;\r\n        beatInfo.metadata = instance.metadata;\r\n        beatInfo.scheduled = false;\r\n\r\n        _objectConfigData->_beatReactor->addBeatInfo(NamingUtils::getGroupedName(serviceName, groupName), beatInfo);\r\n    }\r\n\r\n    _objectConfigData->_serverProxy->registerService(NamingUtils::getGroupedName(serviceName, groupName), groupName, instance);\r\n}\r\n\r\nvoid NacosNamingService::deregisterInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &ip,\r\n                int port\r\n        ) NACOS_THROW(NacosException) {\r\n    deregisterInstance(serviceName, ip, port, ConfigConstant::DEFAULT_CLUSTER_NAME);\r\n}\r\n\r\nvoid NacosNamingService::deregisterInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                const NacosString &ip,\r\n                int port\r\n        ) NACOS_THROW(NacosException) {\r\n    deregisterInstance(serviceName, groupName, ip, port, ConfigConstant::DEFAULT_CLUSTER_NAME);\r\n}\r\n\r\nvoid NacosNamingService::deregisterInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &ip,\r\n                int port,\r\n                const NacosString &clusterName\r\n        ) NACOS_THROW(NacosException) {\r\n    deregisterInstance(serviceName, ConfigConstant::DEFAULT_GROUP, ip, port, clusterName);\r\n}\r\n\r\nvoid NacosNamingService::deregisterInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                const NacosString &ip,\r\n                int port,\r\n                const NacosString &clusterName\r\n        ) NACOS_THROW(NacosException) {\r\n    Instance instance;\r\n    instance.ip = ip;\r\n    instance.port = port;\r\n    instance.clusterName = clusterName;\r\n\r\n    deregisterInstance(serviceName, groupName, instance);\r\n}\r\n\r\nvoid NacosNamingService::deregisterInstance\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                Instance &instance\r\n        ) NACOS_THROW(NacosException) {\r\n    _objectConfigData->_beatReactor->removeBeatInfo(NamingUtils::getGroupedName(serviceName, groupName), instance.ip, instance.port);\r\n    _objectConfigData->_serverProxy->deregisterService(NamingUtils::getGroupedName(serviceName, groupName), instance);\r\n}\r\n\r\nlist <Instance> NacosNamingService::getAllInstances\r\n        (\r\n                const NacosString &serviceName\r\n        ) NACOS_THROW(NacosException) {\r\n    list <NacosString> clusters;\r\n    return getAllInstances(serviceName, clusters);\r\n}\r\n\r\nlist <Instance> NacosNamingService::getAllInstances\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName\r\n        ) NACOS_THROW(NacosException) {\r\n    list <NacosString> clusters;\r\n    return getAllInstances(serviceName, groupName, clusters);\r\n}\r\n\r\nlist <Instance> NacosNamingService::getAllInstances\r\n        (\r\n                const NacosString &serviceName,\r\n                const list <NacosString> &clusters\r\n        ) NACOS_THROW(NacosException) {\r\n    return getAllInstances(serviceName, ConfigConstant::DEFAULT_GROUP, clusters);\r\n}\r\n\r\nlist <Instance> NacosNamingService::getAllInstances\r\n        (\r\n                const NacosString &serviceName,\r\n                const NacosString &groupName,\r\n                const list <NacosString> &clusters\r\n        ) NACOS_THROW(NacosException) {\r\n    ServiceInfo serviceInfo;\r\n    //TODO:cache and failover\r\n    NacosString clusterString = ParamUtils::Implode(clusters);\r\n    NacosString result = _objectConfigData->_serverProxy->queryList(\r\n            serviceName, groupName, clusterString,\r\n            0/*non-zero value to receive subscription push from the server, set to 0 since we don't need it here*/,\r\n            false);\r\n    serviceInfo = JSON::JsonStr2ServiceInfo(result);\r\n    list <Instance> hostlist = serviceInfo.getHosts();\r\n    return hostlist;\r\n}\r\n\r\nvoid NacosNamingService::subscribe(const NacosString &serviceName, EventListener *listener) NACOS_THROW (NacosException)\r\n{\r\n    list<NacosString> clusters;//empty cluster\r\n    subscribe(serviceName, ConfigConstant::DEFAULT_GROUP, clusters, listener);\r\n}\r\n\r\n\r\nvoid NacosNamingService::subscribe\r\n(\r\n    const NacosString &serviceName,\r\n    const NacosString &groupName,\r\n    EventListener *listener\r\n) NACOS_THROW (NacosException)\r\n{\r\n    list<NacosString> clusters;//empty cluster\r\n    subscribe(serviceName, groupName, clusters, listener);\r\n}\r\n\r\nvoid NacosNamingService::subscribe(\r\n    const NacosString &serviceName,\r\n    const std::list<NacosString> &clusters,\r\n    EventListener *listener\r\n) NACOS_THROW (NacosException)\r\n{\r\n    subscribe(serviceName, ConfigConstant::DEFAULT_GROUP, clusters, listener);\r\n}\r\n\r\nvoid NacosNamingService::subscribe\r\n(\r\n        const NacosString &serviceName,\r\n        const NacosString &groupName,\r\n        const std::list<NacosString> &clusters,\r\n        EventListener *listener\r\n) NACOS_THROW (NacosException)\r\n{\r\n    NacosString clusterName = ParamUtils::Implode(clusters);\r\n    NacosString groupedName = NamingUtils::getGroupedName(serviceName, groupName);\r\n    if (!_objectConfigData->_eventDispatcher->addListener(groupedName, clusterName, listener)){\r\n        return;//The listener is already listening to the service specified, no need to add to the polling list\r\n    }\r\n    _objectConfigData->_subscriptionPoller->addPollItem(serviceName, groupName, clusterName);\r\n}\r\n\r\n\r\nvoid NacosNamingService::unsubscribe(\r\n    const NacosString &serviceName,\r\n    const NacosString &groupName,\r\n    const std::list<NacosString> &clusters,\r\n    EventListener *listener\r\n) NACOS_THROW (NacosException)\r\n{\r\n    NacosString clusterName = ParamUtils::Implode(clusters);\r\n    NacosString groupedName = NamingUtils::getGroupedName(serviceName, groupName);\r\n    int remainingListener;\r\n    if (!_objectConfigData->_eventDispatcher->removeListener(groupedName, clusterName, listener, remainingListener)) {\r\n        return;//The listener is not in the list or it is already removed\r\n    }\r\n    if (remainingListener == 0) {\r\n        //Since there's no more listeners listening to this service, remove it from the polling list\r\n        _objectConfigData->_subscriptionPoller->removePollItem(serviceName, groupName, clusterName);\r\n    }\r\n}\r\n\r\nvoid NacosNamingService::unsubscribe\r\n(\r\n    const NacosString &serviceName,\r\n    const std::list<NacosString> &clusters,\r\n    EventListener *listener\r\n) NACOS_THROW (NacosException)\r\n{\r\n    unsubscribe(serviceName, ConfigConstant::DEFAULT_GROUP, clusters, listener);\r\n}\r\n\r\nvoid NacosNamingService::unsubscribe\r\n(\r\n    const NacosString &serviceName,\r\n    const NacosString &groupName,\r\n    EventListener *listener\r\n) NACOS_THROW (NacosException)\r\n{\r\n    list<NacosString> clusters;\r\n    unsubscribe(serviceName, groupName, clusters, listener);\r\n}\r\n\r\nvoid NacosNamingService::unsubscribe(const NacosString &serviceName, EventListener *listener) NACOS_THROW (NacosException)\r\n{\r\n    list<NacosString> clusters;\r\n    unsubscribe(serviceName, ConfigConstant::DEFAULT_GROUP, clusters, listener);\r\n}\r\n\r\nListView<NacosString> NacosNamingService::getServiceList(int pageNo, int pageSize) NACOS_THROW (NacosException) {\r\n    return _objectConfigData->_serverProxy->getServiceList(pageNo, pageSize, ConfigConstant::DEFAULT_GROUP);\r\n}\r\n\r\nListView<NacosString> NacosNamingService::getServiceList(int pageNo, int pageSize, const NacosString &groupName) NACOS_THROW (NacosException){\r\n    return _objectConfigData->_serverProxy->getServiceList(pageNo, pageSize, groupName);\r\n}\r\n\r\nlist<Instance> NacosNamingService::getInstanceWithPredicate\r\n(\r\n    const NacosString &serviceName,\r\n    const NacosString &groupName,\r\n    const std::list <NacosString> &clusters,\r\n    Selector<Instance> *predicate\r\n) NACOS_THROW(NacosException)\r\n{\r\n    list<Instance> allInstances = getAllInstances(serviceName, groupName, clusters);\r\n    if (predicate) {\r\n        return predicate->select(allInstances);\r\n    } else {\r\n        return allInstances;\r\n    }\r\n}\r\n\r\nlist<Instance> NacosNamingService::getInstanceWithPredicate\r\n(\r\n    const NacosString &serviceName,\r\n    const std::list <NacosString> &clusters,\r\n    Selector<Instance> *predicate\r\n) NACOS_THROW(NacosException)\r\n{\r\n    list<Instance> allInstances = getAllInstances(serviceName, ConfigConstant::DEFAULT_GROUP, clusters);\r\n    if (predicate) {\r\n        return predicate->select(allInstances);\r\n    } else {\r\n        return allInstances;\r\n    }\r\n}\r\n\r\nlist<Instance> NacosNamingService::getInstanceWithPredicate\r\n(\r\n    const NacosString &serviceName,\r\n    const NacosString &groupName,\r\n    Selector<Instance> *predicate\r\n) NACOS_THROW(NacosException)\r\n{\r\n    list<NacosString> clusters;\r\n    list<Instance> allInstances = getAllInstances(serviceName, groupName, clusters);\r\n    if (predicate) {\r\n        return predicate->select(allInstances);\r\n    } else {\r\n        return allInstances;\r\n    }\r\n}\r\n\r\nlist<Instance> NacosNamingService::getInstanceWithPredicate\r\n(\r\n    const NacosString &serviceName,\r\n    Selector<Instance> *predicate\r\n) NACOS_THROW(NacosException)\r\n{\r\n    list<NacosString> clusters;\r\n    list<Instance> allInstances = getAllInstances(serviceName, ConfigConstant::DEFAULT_GROUP, clusters);\r\n    if (predicate) {\r\n        return predicate->select(allInstances);\r\n    } else {\r\n        return allInstances;\r\n    }\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/naming/NacosNamingService.h",
    "content": "#ifndef __NACOS_NAM_SVC_H_\n#define __NACOS_NAM_SVC_H_\n\n#include \"naming/NamingService.h\"\n#include \"naming/Instance.h\"\n#include \"src/naming/NamingProxy.h\"\n#include \"src/naming/subscribe/EventDispatcher.h\"\n#include \"src/naming/beat/BeatReactor.h\"\n#include \"src/http/IHttpCli.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass NacosNamingService : public NamingService {\nprivate:\n    ObjectConfigData *_objectConfigData;\n\n    NacosNamingService();\n\n    NacosString cacheDir;\n\n    NacosString logName;\npublic:\n    NacosNamingService(ObjectConfigData *objectConfigData);\n\n    ~NacosNamingService();\n\n    void registerInstance(const NacosString &serviceName, const NacosString &ip, int port) NACOS_THROW(NacosException);\n\n    void registerInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip,\n                          int port) NACOS_THROW(NacosException);\n\n    void registerInstance(const NacosString &serviceName, const NacosString &ip, int port,\n                          const NacosString &clusterName) NACOS_THROW(NacosException);\n\n    void registerInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip, int port,\n                          const NacosString &clusterName) NACOS_THROW(NacosException);\n\n    void registerInstance(const NacosString &serviceName, Instance &instance) NACOS_THROW(NacosException);\n\n    void registerInstance(const NacosString &serviceName, const NacosString &groupName,\n                          Instance &instance) NACOS_THROW(NacosException);\n\n    void deregisterInstance(const NacosString &serviceName, const NacosString &ip, int port) NACOS_THROW(NacosException);\n\n    void deregisterInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip,\n                            int port) NACOS_THROW(NacosException);\n\n    void deregisterInstance(const NacosString &serviceName, const NacosString &ip, int port,\n                            const NacosString &clusterName) NACOS_THROW(NacosException);\n\n    void\n    deregisterInstance(const NacosString &serviceName, const NacosString &groupName, const NacosString &ip, int port,\n                       const NacosString &clusterName) NACOS_THROW(NacosException);\n\n    void deregisterInstance(const NacosString &serviceName, const NacosString &groupName,\n                            Instance &instance) NACOS_THROW(NacosException);\n\n    std::list <Instance> getAllInstances(const NacosString &serviceName) NACOS_THROW(NacosException);\n\n    std::list <Instance>\n    getAllInstances(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException);\n\n    std::list <Instance>\n    getAllInstances(const NacosString &serviceName, const std::list <NacosString> &clusters) NACOS_THROW(NacosException);\n\n    std::list <Instance> getAllInstances(const NacosString &serviceName, const NacosString &groupName,\n                                         const std::list <NacosString> &clusters) NACOS_THROW(NacosException);\n\n    void subscribe(const NacosString &serviceName, EventListener *listener) NACOS_THROW (NacosException);\n\n    void subscribe(const NacosString &serviceName, const NacosString &groupName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException);\n\n    void subscribe(const NacosString &serviceName, const NacosString &groupName, EventListener *listener) NACOS_THROW (NacosException);\n\n    void subscribe(const NacosString &serviceName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException);\n\n    void unsubscribe(const NacosString &serviceName, EventListener *listener) NACOS_THROW (NacosException);\n\n    void unsubscribe(const NacosString &serviceName, const NacosString &groupName, EventListener *listener) NACOS_THROW (NacosException);\n\n    void unsubscribe(const NacosString &serviceName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException);\n\n    void unsubscribe(const NacosString &serviceName, const NacosString &groupName, const std::list<NacosString> &clusters, EventListener *listener) NACOS_THROW (NacosException);\n\n    ListView<NacosString> getServiceList(int pageNo, int pageSize) NACOS_THROW (NacosException);\n\n    ListView<NacosString> getServiceList(int pageNo, int pageSize, const NacosString &groupName) NACOS_THROW (NacosException);\n\n    std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName, const NacosString &groupName,\n                                                 const std::list <NacosString> &clusters,\n                                                 nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException);\n\n    std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName,\n                                                 const std::list <NacosString> &clusters,\n                                                 nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException);\n\n    std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName, const NacosString &groupName,\n                                                 nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException);\n\n    std::list<Instance> getInstanceWithPredicate(const NacosString &serviceName,\n                                                 nacos::naming::selectors::Selector<Instance> *predicate) NACOS_THROW(NacosException);\n\n    IHttpCli *getHttpCli() const { return _objectConfigData->_httpCli; };\n\n    NamingProxy *getServerProxy() const { return _objectConfigData->_serverProxy; };\n\n    BeatReactor *getBeatReactor() const { return _objectConfigData->_beatReactor; };\n\n    void setHttpCli(IHttpCli *httpCli) { this->_objectConfigData->_httpCli = httpCli; };\n\n    void setServerProxy(NamingProxy *_namingProxy) { this->_objectConfigData->_serverProxy = _namingProxy; };\n\n    void setBeatReactor(BeatReactor *_beatReactor) { this->_objectConfigData->_beatReactor = _beatReactor; };\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/naming/NamingProxy.cpp",
    "content": "#include <map>\r\n#include \"NamingProxy.h\"\r\n#include \"constant/NamingConstant.h\"\r\n#include \"constant/UtilAndComs.h\"\r\n#include \"src/utils/UuidUtils.h\"\r\n#include \"src/utils/ParamUtils.h\"\r\n#include \"src/utils/url.h\"\r\n#include \"src/utils/RandomUtils.h\"\r\n#include \"src/json/JSON.h\"\r\n#include \"src/http/HttpStatus.h\"\r\n#include \"NacosExceptions.h\"\r\n#include \"src/crypto/SignatureTool.h\"\r\n\r\nusing namespace std;\r\n\r\nnamespace nacos{\r\n\r\nListView<NacosString> NamingProxy::nullResult;\r\n\r\nNamingProxy::NamingProxy(ObjectConfigData *objectConfigData) {\r\n    _objectConfigData = objectConfigData;\r\n    log_debug(\"NamingProxy Constructor:\\n\"\r\n              \"namespace:%s, endpoint:%s, Servers:%s\\n\",\r\n              objectConfigData->_serverListManager->getNamespace().c_str(), objectConfigData->_serverListManager->getEndpoint().c_str(),\r\n              objectConfigData->_serverListManager->toString().c_str());\r\n    serverPort = \"8848\";\r\n\r\n    if (objectConfigData->_serverListManager->getServerCount() == 1) {\r\n        nacosDomain = objectConfigData->_serverListManager->getServerList().begin()->getCompleteAddress();\r\n    }\r\n    log_debug(\"The serverlist:%s\\n\", objectConfigData->_serverListManager->toString().c_str());\r\n\r\n    nullResult.setCount(0);\r\n    _hb_fail_wait = atoi(objectConfigData->_appConfigManager->get(PropertyKeyConst::HB_FAIL_WAIT_TIME).c_str());\r\n}\r\n\r\nNamingProxy::~NamingProxy() {\r\n}\r\n\r\nvoid NamingProxy::registerService(const NacosString &serviceName, const NacosString &groupName,\r\n                                  Instance &instance) NACOS_THROW(NacosException) {\r\n    log_info(\"[REGISTER-SERVICE] %s registering service %s with instance: %s\\n\",\r\n             getNamespaceId().c_str(), serviceName.c_str(), instance.toString().c_str());\r\n\r\n    list <NacosString> params;\r\n    ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, serviceName);\r\n    ParamUtils::addKV(params, NamingConstant::GROUP_NAME, groupName);\r\n    ParamUtils::addKV(params, NamingConstant::CLUSTER_NAME, instance.clusterName);\r\n    ParamUtils::addKV(params, \"ip\", instance.ip);\r\n    ParamUtils::addKV(params, \"port\",  NacosStringOps::valueOf(instance.port));\r\n    ParamUtils::addKV(params, \"weight\", NacosStringOps::valueOf(instance.weight));\r\n    ParamUtils::addKV(params, \"enable\", NacosStringOps::valueOf(instance.enabled));\r\n    ParamUtils::addKV(params, NamingConstant::HEALTHY, NacosStringOps::valueOf(instance.healthy));\r\n    ParamUtils::addKV(params, \"ephemeral\", NacosStringOps::valueOf(instance.ephemeral));\r\n    ParamUtils::addKV(params, \"metadata\", JSON::toJSONString(instance.metadata));\r\n\r\n    reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_INSTANCE, params, IHttpCli::POST);\r\n}\r\n\r\nvoid NamingProxy::deregisterService(const NacosString &serviceName, Instance &instance) NACOS_THROW(NacosException) {\r\n    log_info(\"[DEREGISTER-SERVICE] %s deregistering service %s with instance: %s\\n\",\r\n             getNamespaceId().c_str(), serviceName.c_str(), instance.toString().c_str());\r\n\r\n    list <NacosString> params;\r\n    ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, serviceName);\r\n    ParamUtils::addKV(params, NamingConstant::CLUSTER_NAME, instance.clusterName);\r\n    ParamUtils::addKV(params, \"ip\", instance.ip);\r\n    ParamUtils::addKV(params, \"port\",  NacosStringOps::valueOf(instance.port));\r\n    ParamUtils::addKV(params, \"ephemeral\", NacosStringOps::valueOf(instance.ephemeral));\r\n\r\n    reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_INSTANCE, params, IHttpCli::DELETE);\r\n}\r\n\r\nNacosString NamingProxy::queryList(const NacosString &serviceName, const NacosString &groupName, const NacosString &clusters,\r\n                                    int udpPort, bool healthyOnly) NACOS_THROW(NacosException) {\r\n    list <NacosString> params;\r\n    const NacosString &localIp = _objectConfigData->_appConfigManager->get(PropertyKeyConst::LOCAL_IP);\r\n    ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, serviceName);\r\n    ParamUtils::addKV(params, NamingConstant::GROUP_NAME, groupName);\r\n    ParamUtils::addKV(params, NamingConstant::CLUSTERS, clusters);\r\n    ParamUtils::addKV(params, NamingConstant::UDP_PORT, NacosStringOps::valueOf(udpPort));\r\n    ParamUtils::addKV(params, NamingConstant::CLIENT_IP, localIp);\r\n    ParamUtils::addKV(params, NamingConstant::HEALTHY_ONLY, NacosStringOps::valueOf(healthyOnly));\r\n\r\n    return reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/instance/list\", params, IHttpCli::GET);\r\n}\r\n\r\nNacosString\r\nNamingProxy::reqAPI(const NacosString &api, list <NacosString> &params, int method) NACOS_THROW(NacosException) {\r\n    ServerListManager *_serverListManager = _objectConfigData->_serverListManager;\r\n    list <NacosServerInfo> servers = _serverListManager->getServerList();\r\n\r\n    if (_serverListManager->getServerCount() == 0) {\r\n        throw NacosException(NacosException::NO_SERVER_AVAILABLE, \"no server available\");\r\n    }\r\n\r\n    NacosString errmsg;\r\n    if (!servers.empty()) {\r\n        size_t maxSvrSlot = servers.size();\r\n        log_debug(\"nr_servers:%d\\n\", maxSvrSlot);\r\n        size_t selectedServer = RandomUtils::random(0, maxSvrSlot) % maxSvrSlot;\r\n        log_debug(\"selected_server:%d\\n\", selectedServer);\r\n\r\n        for (size_t i = 0; i < servers.size(); i++) {\r\n            const NacosServerInfo &server = ParamUtils::getNthElem(servers, selectedServer);\r\n            log_debug(\"Trying to access server:%s\\n\", server.toString().c_str());\r\n            try {\r\n                return callServer(api, params, server.getCompleteAddress(), method);\r\n            }\r\n            catch (NacosException &e) {\r\n                errmsg = e.what();\r\n                log_error(\"request %s failed.\\n\", server.toString().c_str());\r\n            }\r\n            catch (exception &e) {\r\n                errmsg = e.what();\r\n                log_error(\"request %s failed.\\n\", server.toString().c_str());\r\n            }\r\n\r\n            selectedServer = (selectedServer + 1) % servers.size();\r\n        }\r\n\r\n        throw NacosException(NacosException::ALL_SERVERS_TRIED_AND_FAILED, \"failed to req API:\" + api + \" after all servers(\" + _serverListManager->toString() +\r\n                                \") tried: \"\r\n                                + errmsg);\r\n    }\r\n\r\n    for (int i = 0; i < UtilAndComs::REQUEST_DOMAIN_RETRY_COUNT; i++) {\r\n        try {\r\n            return callServer(api, params, nacosDomain);\r\n        }\r\n        catch (exception &e) {\r\n            errmsg = e.what();\r\n            log_error(\"[NA] req api:%s failed, server(%s), e = %s\\n\", api.c_str(), nacosDomain.c_str(), e.what());\r\n        }\r\n    }\r\n\r\n    throw NacosException(NacosException::ALL_SERVERS_TRIED_AND_FAILED, \"failed to req API:/api/\" + api + \" after all servers(\" + _serverListManager->toString() +\r\n                            \") tried: \" + errmsg);\r\n}\r\n\r\nNacosString NamingProxy::callServer\r\n        (\r\n                const NacosString &api,\r\n                list <NacosString> &params,\r\n                const NacosString &curServer\r\n        ) NACOS_THROW(NacosException) {\r\n    return callServer(api, params, nacosDomain, IHttpCli::GET);\r\n}\r\n\r\nNacosString NamingProxy::getDataToSign(const std::list <NacosString> &paramValues, NacosString &nowTimeMs) {\r\n    const NacosString &serviceName = ParamUtils::findByKey(paramValues, NamingConstant::SERVICE_NAME);\r\n    const NacosString &groupName = ParamUtils::findByKey(paramValues, NamingConstant::GROUP_NAME);\r\n\r\n    NacosString dataToSign = \"\";\r\n    if ((!ParamUtils::isBlank(serviceName) && serviceName.find(NamingConstant::SPLITER) != std::string::npos) || ParamUtils::isBlank(groupName)) {\r\n        dataToSign = nowTimeMs + NamingConstant::SPLITER + serviceName;\r\n    } else {\r\n        dataToSign = nowTimeMs + NamingConstant::SPLITER + groupName + NamingConstant::SPLITER + serviceName;\r\n    }\r\n    return dataToSign;\r\n}\r\n\r\nNacosString NamingProxy::callServer\r\n        (\r\n                const NacosString &api,\r\n                list <NacosString> &params,\r\n                const NacosString &curServer,\r\n                int method\r\n        ) NACOS_THROW(NacosException) {\r\n    NacosString requestUrl;\r\n    //Current server address doesn't have SERVER_ADDR_IP_SPLITER, which means\r\n    if (!ParamUtils::contains(curServer, UtilAndComs::SERVER_ADDR_IP_SPLITER)) {\r\n        requestUrl = curServer + UtilAndComs::SERVER_ADDR_IP_SPLITER + serverPort;\r\n    } else {\r\n        requestUrl = curServer;\r\n    }\r\n\r\n    //TODO:http/https implementation\r\n    requestUrl = requestUrl + api;\r\n\r\n    HttpResult requestRes;\r\n    list <NacosString> headers;\r\n    headers = builderHeaders();\r\n\r\n    //SPAS security\r\n    NacosString secretKey = _objectConfigData->_appConfigManager->get(PropertyKeyConst::SECRET_KEY);\r\n    NacosString accessKey = _objectConfigData->_appConfigManager->get(PropertyKeyConst::ACCESS_KEY);\r\n\r\n    //If SPAS security credentials are set, SPAS is enabled\r\n    if (!ParamUtils::isBlank(secretKey) && !ParamUtils::isBlank(accessKey)) {\r\n        NacosString nowTimeMs = NacosStringOps::valueOf(TimeUtils::getCurrentTimeInMs());\r\n        NacosString dataToSign = getDataToSign(params, nowTimeMs);\r\n        NacosString signature = SignatureTool::SignWithHMAC_SHA1(dataToSign, secretKey);\r\n        //inject security credentials\r\n        if (method == IHttpCli::GET || method == IHttpCli::DELETE) {\r\n            ParamUtils::addKV(params, \"signature\", signature);\r\n            ParamUtils::addKV(params, \"data\", dataToSign);\r\n            ParamUtils::addKV(params, \"ak\", accessKey);\r\n        } else {\r\n            requestUrl = requestUrl + \"?signature=\" + urlencode(signature) + \"&data=\" + dataToSign + \"&ak=\" + accessKey;\r\n        }\r\n    }\r\n\r\n    HttpDelegate *_httpDelegate = _objectConfigData->_httpDelegate;\r\n    \r\n    try {\r\n        long _http_req_timeout = _objectConfigData->_appConfigManager->getServeReqTimeout();\r\n        switch (method) {\r\n            case IHttpCli::GET:\r\n                requestRes = _httpDelegate->httpGet(requestUrl, headers, params, UtilAndComs::ENCODING,\r\n                                              _http_req_timeout);\r\n                break;\r\n            case IHttpCli::PUT:\r\n                requestRes = _httpDelegate->httpPut(requestUrl, headers, params, UtilAndComs::ENCODING,\r\n                                              _http_req_timeout);\r\n                break;\r\n            case IHttpCli::POST:\r\n                requestRes = _httpDelegate->httpPost(requestUrl, headers, params, UtilAndComs::ENCODING,\r\n                                               _http_req_timeout);\r\n                break;\r\n            case IHttpCli::DELETE:\r\n                requestRes = _httpDelegate->httpDelete(requestUrl, headers, params, UtilAndComs::ENCODING,\r\n                                                 _http_req_timeout);\r\n                break;\r\n        }\r\n    }\r\n    catch (NetworkException &e) {\r\n        NacosString errMsg = \"Failed to request server, \";\r\n        errMsg += e.what();\r\n        throw NacosException(NacosException::SERVER_ERROR, errMsg);\r\n    }\r\n\r\n    if (requestRes.code == HttpStatus::HTTP_OK) {\r\n        return requestRes.content;\r\n    }\r\n\r\n    if (requestRes.code == HttpStatus::HTTP_NOT_MODIFIED) {\r\n        return NULLSTR;\r\n    }\r\n    //TODO:Metrics & Monitoring\r\n\r\n    throw NacosException(requestRes.code,\r\n                         \"failed to req API:\" + requestUrl + \" code:\" + NacosStringOps::valueOf(requestRes.code) +\r\n                         \" errormsg:\" + requestRes.content);\r\n}\r\n\r\ninline NacosString NamingProxy::getNamespaceId() {\r\n    return _objectConfigData->_appConfigManager->get(PropertyKeyConst::NAMESPACE);\r\n}\r\n\r\nlist <NacosString> NamingProxy::builderHeaders() {\r\n    list <NacosString> headers;\r\n    headers.push_back(\"Client-Version\");\r\n    headers.push_back(UtilAndComs::VERSION);\r\n\r\n    headers.push_back(\"Accept-Encoding\");\r\n    headers.push_back(\"gzip,deflate,sdch\");\r\n\r\n    headers.push_back(\"Connection\");\r\n    headers.push_back(\"Keep-Alive\");\r\n\r\n    headers.push_back(\"RequestId\");\r\n    headers.push_back(UuidUtils::generateUuid());\r\n\r\n    headers.push_back(\"Request-Module\");\r\n    headers.push_back(\"Naming\");\r\n    return headers;\r\n}\r\n\r\nlong NamingProxy::sendBeat(BeatInfo &beatInfo) {\r\n    try {\r\n        NacosString beatInfoStr = beatInfo.toString();\r\n        log_info(\"[BEAT] %s sending beat to server: %s\\n\", getNamespaceId().c_str(), beatInfoStr.c_str());\r\n        list <NacosString> params;\r\n        ParamUtils::addKV(params, NamingConstant::BEAT, JSON::toJSONString(beatInfo));\r\n        ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n        ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, beatInfo.serviceName);\r\n        NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/instance/beat\", params, IHttpCli::PUT);\r\n        //JSONObject jsonObject = JSON.parseObject(result);\r\n\r\n        if (!isNull(result)) {\r\n            return JSON::getLong(result, \"clientBeatInterval\");\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        NacosString jsonBeatInfo = JSON::toJSONString(beatInfo);\r\n        log_error(\"[CLIENT-BEAT] failed to send beat: %s e:%s\\n\", jsonBeatInfo.c_str(), e.what());\r\n        return _hb_fail_wait;\r\n    }\r\n    return 0L;\r\n}\r\n\r\nListView<NacosString> NamingProxy::getServiceList(int page, int pageSize, const NacosString &groupName) NACOS_THROW(NacosException)\r\n{\r\n    log_debug(\"[NAMEPRXY] request:group=%s page=%d pageSize=%d\\n\", groupName.c_str(), page, pageSize);\r\n    list <NacosString> params;\r\n    ParamUtils::addKV(params, NamingConstant::PAGE_NO, NacosStringOps::valueOf(page));\r\n    ParamUtils::addKV(params, NamingConstant::PAGE_SIZE, NacosStringOps::valueOf(pageSize));\r\n    ParamUtils::addKV(params, NamingConstant::GROUP_NAME, groupName);\r\n    ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/service/list\", params, IHttpCli::GET);\r\n\r\n    if (!isNull(result)) {\r\n        return JSON::Json2ServiceList(result);\r\n    }\r\n\r\n    return nullResult;\r\n}\r\n\r\nServiceInfo2 NamingProxy::getServiceInfo(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException)\r\n{\r\n    log_debug(\"[NAMEPRXY] getServiceInfo request:serviceName=%s groupName=%s\\n\",\r\n              serviceName.c_str(), groupName.c_str());\r\n    list <NacosString> params;\r\n    ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, serviceName);\r\n    if (!NacosStringOps::isNullStr(groupName)) {\r\n        ParamUtils::addKV(params, NamingConstant::GROUP_NAME, groupName);\r\n    } else {\r\n        ParamUtils::addKV(params, NamingConstant::GROUP_NAME, ConfigConstant::DEFAULT_GROUP);\r\n    }\r\n    ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/service\", params, IHttpCli::GET);\r\n    log_debug(\"NamingProxy::getServiceInfo: service info from server:%s\\n\", result.c_str());\r\n\r\n    if (!isNull(result)) {\r\n        return JSON::Json2ServiceInfo2(result);\r\n    }\r\n\r\n    return ServiceInfo2::nullServiceInfo2;\r\n}\r\n\r\nbool areYouOk(const NacosString &imVeryOk) {\r\n    if (imVeryOk.compare(\"ok\") == 0) {\r\n        return true;\r\n    } else {\r\n        return false;\r\n    }\r\n}\r\n\r\n/**\r\n * removes a service info from nacos server\r\n * please note that the operation will succeed ONLY WHEN there's NO instance of the service specified\r\n *\r\n * @param serviceName service name\r\n * @param groupName   group name\r\n * @return true if operation succeeds\r\n *         otherwise return false\r\n * @throws IOException IOException\r\n */\r\nbool NamingProxy::deleteServiceInfo(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException) {\r\n    list<NacosString> params;\r\n    ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, serviceName);\r\n    ParamUtils::addKV(params, NamingConstant::GROUP_NAME, groupName);\r\n    ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/service\", params, IHttpCli::DELETE);\r\n\r\n    return areYouOk(result);\r\n}\r\n\r\nvoid assembleServiceInfoRequest(list<NacosString> &target, const ServiceInfo2 &serviceInfo2) {\r\n    if (serviceInfo2.isNameSet()) {\r\n        ParamUtils::addKV(target, NamingConstant::SERVICE_NAME, serviceInfo2.getName());\r\n    }\r\n    if (serviceInfo2.isGroupNameSet()) {\r\n        ParamUtils::addKV(target, NamingConstant::GROUP_NAME, serviceInfo2.getGroupName());\r\n    }\r\n    if (serviceInfo2.isNamespaceIdSet()) {\r\n        ParamUtils::addKV(target, NamingConstant::NAMESPACE_ID, serviceInfo2.getNamespaceId());\r\n    }\r\n    if (serviceInfo2.isProtectThresholdSet()) {\r\n        ParamUtils::addKV(target, \"protectThreshold\", NacosStringOps::valueOf(serviceInfo2.getProtectThreshold()));\r\n    }\r\n    if (serviceInfo2.isMetadataSet()) {\r\n        ParamUtils::addKV(target, \"metadata\", JSON::toJSONString(serviceInfo2.getMetadata()));\r\n    }\r\n}\r\n\r\nbool NamingProxy::createServiceInfo(const ServiceInfo2 &serviceInfo2, naming::Selector *selector) NACOS_THROW(NacosException) {\r\n    list<NacosString> params;\r\n    assembleServiceInfoRequest(params, serviceInfo2);\r\n    if (selector) {\r\n        ParamUtils::addKV(params, \"selector\", selector->getSelectorString());\r\n    }\r\n\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/service\", params, IHttpCli::POST);\r\n    return areYouOk(result);\r\n}\r\n\r\nbool NamingProxy::updateServiceInfo(const ServiceInfo2 &serviceInfo2, naming::Selector *selector) NACOS_THROW(NacosException) {\r\n    list<NacosString> params;\r\n    assembleServiceInfoRequest(params, serviceInfo2);\r\n    if (selector) {\r\n        ParamUtils::addKV(params, \"selector\", selector->getSelectorString());\r\n    }\r\n\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/service\", params, IHttpCli::PUT);\r\n    return areYouOk(result);\r\n}\r\n\r\nbool NamingProxy::serverHealthy() {\r\n    list<NacosString> params;\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/operator/metrics\", params, IHttpCli::GET);\r\n    NacosString healthyTag = \"status\\\":\\\"\";\r\n    size_t pos = result.find(healthyTag);\r\n    if (pos == std::string::npos) {\r\n        return false;\r\n    }\r\n\r\n    NacosString healthy = result.substr(pos + healthyTag.length(), 2);\r\n    return healthy == \"UP\";\r\n}\r\n\r\n/**\r\n * gets one service instance info from nacos server\r\n *\r\n * @param serviceName service name\r\n * @param ip          ip address\r\n * @param port        port\r\n * @param params      optional parameters, options are:\r\n * groupName\r\n * namespaceId\r\n * cluster\r\n * healthyOnly\r\n * ephemeral\r\n * @return Instance info if succeed, nullObj if fails\r\n * @throws NacosException NacosException\r\n */\r\nInstance NamingProxy::getServiceInstance\r\n(\r\n    const NacosString &serviceName,\r\n    const NacosString &ip,\r\n    int port,\r\n    const std::map<NacosString, NacosString> &params\r\n)\r\nNACOS_THROW(NacosException) {\r\n    list<NacosString> paramsList;\r\n    ParamUtils::addKV(paramsList, NamingConstant::SERVICE_NAME, serviceName);\r\n    ParamUtils::addKV(paramsList, \"ip\", ip);\r\n    ParamUtils::addKV(paramsList, \"port\", NacosStringOps::valueOf(port));\r\n\r\n    for (map<NacosString, NacosString>::const_iterator it = params.begin();\r\n        it != params.end(); it++) {\r\n        ParamUtils::addKV(paramsList, it->first, it->second);\r\n    }\r\n\r\n    if (params.count(NamingConstant::NAMESPACE_ID) == 0) {\r\n        ParamUtils::addKV(paramsList, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    }\r\n\r\n    if (params.count(NamingConstant::GROUP_NAME) == 0) {\r\n        ParamUtils::addKV(paramsList, NamingConstant::GROUP_NAME, ConfigConstant::DEFAULT_GROUP);\r\n    }\r\n\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/instance\", paramsList, IHttpCli::GET);\r\n\r\n    return JSON::Json2Instance(result);\r\n}\r\n\r\nbool NamingProxy::updateServiceInstance(const Instance &instance) NACOS_THROW(NacosException) {\r\n    list<NacosString> params;\r\n    ParamUtils::addKV(params, NamingConstant::SERVICE_NAME, instance.serviceName);\r\n    ParamUtils::addKV(params, \"ip\", instance.ip);\r\n    ParamUtils::addKV(params, \"port\", NacosStringOps::valueOf(instance.port));\r\n\r\n    if (NacosStringOps::isNullStr(instance.groupName)) {\r\n        ParamUtils::addKV(params, NamingConstant::GROUP_NAME, ConfigConstant::DEFAULT_GROUP);\r\n    } else {\r\n        ParamUtils::addKV(params, NamingConstant::GROUP_NAME, instance.groupName);\r\n    }\r\n\r\n    if (NacosStringOps::isNullStr(instance.namespaceId)) {\r\n        ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, getNamespaceId());\r\n    } else {\r\n        ParamUtils::addKV(params, NamingConstant::NAMESPACE_ID, instance.namespaceId);\r\n    }\r\n\r\n    if (!NacosStringOps::isNullStr(instance.clusterName)) {\r\n        ParamUtils::addKV(params, NamingConstant::CLUSTER_NAME, instance.clusterName);\r\n    }\r\n\r\n    if (instance.metadata.size() > 0) {\r\n        ParamUtils::addKV(params, \"metadata\", JSON::toJSONString(instance.metadata));\r\n    }\r\n    ParamUtils::addKV(params, \"ephemeral\", NacosStringOps::valueOf(instance.ephemeral));\r\n    //TODO:weight is optional\r\n    ParamUtils::addKV(params, \"weight\", NacosStringOps::valueOf(instance.weight));\r\n\r\n    NacosString result = reqAPI(\"/\" + _objectConfigData->_appConfigManager->getContextPath() + UtilAndComs::NACOS_URL_BASE + \"/instance\", params, IHttpCli::PUT);\r\n\r\n    return areYouOk(result);\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/naming/NamingProxy.h",
    "content": "#ifndef __NAMING_PROXY_H_\n#define __NAMING_PROXY_H_\n\n#include <map>\n#include <list>\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"naming/Instance.h\"\n#include \"src/naming/beat/BeatInfo.h\"\n#include \"src/server/ServerListManager.h\"\n#include \"naming/ListView.h\"\n#include \"naming/ServiceInfo2.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass NamingProxy {\nprivate:\n    NacosString serverPort;\n    ObjectConfigData *_objectConfigData;\n\n    NacosString nacosDomain;\n\n    NamingProxy();\n\n    NacosString\n    reqAPI(const NacosString &api, std::list <NacosString> &params, int method) NACOS_THROW(NacosException);\n\n    NacosString\n    callServer(const NacosString &api, std::list <NacosString> &params, const NacosString &curServer,\n               int method) NACOS_THROW(NacosException);\n\n    NacosString callServer(const NacosString &api, std::list <NacosString> &params,\n                           const NacosString &curServer) NACOS_THROW(NacosException);\n\n    std::list <NacosString> builderHeaders();\n\n    long _hb_fail_wait;//Time to wait when a heartbeat request fails (in ms)\n\n    static ListView<NacosString> nullResult;\n\n    NacosString getDataToSign(const std::list <NacosString> &paramValues, NacosString &nowTimeMs);\n\npublic:\n    NamingProxy(ObjectConfigData *objectConfigData);\n\n    ~NamingProxy();\n\n    //instance CRUD\n    void registerService(const NacosString &serviceName, const NacosString &groupName,\n                         Instance &instance) NACOS_THROW(NacosException);\n\n    Instance getServiceInstance(const NacosString &serviceName,\n                                const NacosString &ip, int port,\n                                const std::map<NacosString, NacosString> &params) NACOS_THROW(NacosException);\n\n    bool updateServiceInstance(const Instance &instance) NACOS_THROW(NacosException);\n\n    void deregisterService(const NacosString &serviceName, Instance &instance) NACOS_THROW(NacosException);\n\n    NacosString queryList(const NacosString &serviceName, const NacosString &groupName, const NacosString &clusters,\n                        int udpPort, bool healthyOnly) NACOS_THROW(NacosException);\n\n    //service CRUD\n    ListView<NacosString> getServiceList(int page, int pageSize, const NacosString &groupName) NACOS_THROW(NacosException);\n\n    ServiceInfo2 getServiceInfo(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException);\n\n    bool deleteServiceInfo(const NacosString &serviceName, const NacosString &groupName) NACOS_THROW(NacosException);\n\n    bool createServiceInfo(const ServiceInfo2 &serviceInfo2, naming::Selector *selector) NACOS_THROW(NacosException);\n\n    bool updateServiceInfo(const ServiceInfo2 &serviceInfo2, naming::Selector *selector) NACOS_THROW(NacosException);\n\n    inline NacosString getNamespaceId();\n\n    long sendBeat(BeatInfo &beatInfo);\n\n    bool serverHealthy();\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/naming/ServiceInfo.cpp",
    "content": "#include \"naming/ServiceInfo.h\"\n#include <vector>\n#include <list>\n#include <sys/time.h>\n#include \"NacosString.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"src/utils/url.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"naming/Instance.h\"\nnamespace nacos{\nServiceInfo::ServiceInfo() : _jsonFromServer(\"\"), _cacheMillis(1000L), _lastRefTime(0L), _checksum(\"\"), _allIPs(false) {\n}\n\nbool ServiceInfo::isAllIPs() const{\n    return _allIPs;\n}\n\nvoid ServiceInfo::setAllIPs(bool allIPs) {\n    _allIPs = allIPs;\n}\n\nServiceInfo::ServiceInfo(const NacosString &key)  : _jsonFromServer(\"\"), _cacheMillis(1000L), _lastRefTime(0L), _checksum(\"\"),\n                                        _allIPs(false) {\n    std::vector <NacosString> segs;\n    ParamUtils::Explode(segs, key, ConfigConstant::SERVICE_INFO_SPLITER);\n\n    if (segs.size() == 2) {\n        setGroupName(segs[0]);\n        setName(segs[1]);\n    } else if (segs.size() == 3) {\n        setGroupName(segs[0]);\n        setName(segs[1]);\n        setClusters(segs[2]);\n    }\n}\n\nServiceInfo::ServiceInfo(const NacosString &name, const NacosString &clusters) {\n    _name = name;\n    _clusters = clusters;\n}\n\nint ServiceInfo::ipCount() {\n    return _hosts.size();\n}\n\nbool ServiceInfo::expired() const{\n    //TODO:extract this snippet to a common util\n    struct timeval tp;\n    gettimeofday(&tp, NULL);\n    long int ms = tp.tv_sec * 1000 + tp.tv_usec / 1000;\n\n    return ms - _lastRefTime > _cacheMillis;\n}\n\nvoid ServiceInfo::setHosts(std::list <Instance> &hosts) {\n    _hosts = hosts;\n}\n\nbool ServiceInfo::isValid() {\n    return _hosts.size() > 0;\n}\n\nNacosString ServiceInfo::getName() {\n    return _name;\n}\n\nvoid ServiceInfo::setName(const NacosString &name) {\n    _name = name;\n}\n\nNacosString ServiceInfo::getGroupName() {\n    return _groupName;\n}\n\nvoid ServiceInfo::setGroupName(const NacosString &groupName) {\n    _groupName = groupName;\n}\n\nvoid ServiceInfo::setLastRefTime(long lastRefTime) {\n    _lastRefTime = lastRefTime;\n}\n\nlong ServiceInfo::getLastRefTime() {\n    return _lastRefTime;\n}\n\nNacosString ServiceInfo::getClusters() {\n    return _clusters;\n}\n\nvoid ServiceInfo::setClusters(const NacosString &clusters) {\n    _clusters = clusters;\n}\n\nlong ServiceInfo::getCacheMillis() {\n    return _cacheMillis;\n}\n\nvoid ServiceInfo::setCacheMillis(long cacheMillis) {\n    _cacheMillis = cacheMillis;\n}\n\nstd::list <Instance> ServiceInfo::getHosts() {\n    return _hosts;\n}\n\nstd::list <Instance> *ServiceInfo::getHostsNocopy() {\n    return &_hosts;\n}\n\nbool ServiceInfo::validate() const{\n    if (isAllIPs()) {\n        return true;\n    }\n\n    //TODO: Idk what does this mean in Java, ignore in C++\n    /*std::list<Instance> validHosts;\n    for (std::list<Instance>::iterator it = _hosts.begin()\n    it != _hosts.end(); it++)\n    {\n        if (it->isHealthy())\n        {\n            continue;\n        }\n\n        for (int i = 0; i < it->getWeight(); i++)\n        {\n            validHosts.push_back(*it);\n        }\n    }*/\n\n    return true;\n}\n\n//@JSONField(serialize = false)\nNacosString ServiceInfo::getJsonFromServer() const{\n    return _jsonFromServer;\n}\n\nvoid ServiceInfo::setJsonFromServer(const NacosString &jsonFromServer) {\n    _jsonFromServer = jsonFromServer;\n}\n\n//@JSONField(serialize = false)\nNacosString ServiceInfo::getKey() const{\n    return getKey(_name, _clusters);\n}\n\n//@JSONField(serialize = false)\nNacosString ServiceInfo::getKeyEncoded() const{\n    return getKey(urlencode(_name), _clusters);\n}\n\n//@JSONField(serialize = false)\nvoid ServiceInfo::fromKey(ServiceInfo &serviceInfo, const NacosString &key) {\n    std::vector <NacosString> segs;\n    ParamUtils::Explode(segs, key, ConfigConstant::SERVICE_INFO_SPLITER);\n\n    if (segs.size() == 2) {\n        serviceInfo.setGroupName(segs[0]);\n        serviceInfo.setName(segs[1]);\n    } else if (segs.size() == 3) {\n        serviceInfo.setGroupName(segs[0]);\n        serviceInfo.setName(segs[1]);\n        serviceInfo.setClusters(segs[2]);\n    }\n}\n\n//@JSONField(serialize = false)\nNacosString ServiceInfo::getKey(const NacosString &name, const NacosString &clusters) {\n    if (!ParamUtils::isBlank(clusters)) {\n        return name + ConfigConstant::SERVICE_INFO_SPLITER + clusters;\n    }\n\n    return name;\n}\n\n//@Override\nNacosString ServiceInfo::toString() const{\n    return getKey();\n}\n\n//!!BE CAREFUL!!\n//This function is very expensive!! call it with care!\nNacosString ServiceInfo::toInstanceString() const{\n    NacosString res = \"{\\\"lastRefTime\\\":\" + NacosStringOps::valueOf(_lastRefTime) + \" [\\n\";\n    for (std::list<Instance>::const_iterator it = _hosts.begin();\n        it != _hosts.end(); it++)\n    {\n        res += it->toString() + \"\\n\";\n    }\n\n    res += \"\\n]}\";\n\n    return res;\n}\n\nNacosString ServiceInfo::getChecksum() const{\n    return _checksum;\n}\n\nvoid ServiceInfo::setChecksum(const NacosString &checksum) {\n    _checksum = checksum;\n}\n\n}"
  },
  {
    "path": "src/naming/beat/BeatInfo.cpp",
    "content": "#include \"src/json/JSON.h\"\r\n#include \"BeatInfo.h\"\r\n#include \"NacosString.h\"\r\n\r\nnamespace nacos{\r\nNacosString BeatInfo::toString() {\r\n    return JSON::toJSONString(*this);\r\n}\r\n}//namespace nacos"
  },
  {
    "path": "src/naming/beat/BeatInfo.h",
    "content": "#ifndef __BEAT_INFO_H_\n#define __BEAT_INFO_H_\n\n#include <map>\n#include \"NacosString.h\"\n\n/*\n * Copyright 1999-2018 Alibaba Group Holding Ltd.\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.\n */\n\n/**\n * @author nkorange\n */\nnamespace nacos{\nclass BeatInfo {\npublic:\n    int port;\n    NacosString ip;\n    double weight;\n    NacosString serviceName;\n    NacosString cluster;\n    std::map <NacosString, NacosString> metadata;\n    volatile bool scheduled;\n    volatile long nextHbTime;\n\n    NacosString toString();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/naming/beat/BeatReactor.cpp",
    "content": "#include <map>\r\n#include \"BeatReactor.h\"\r\n#include \"BeatTask.h\"\r\n#include \"NacosString.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n\r\nusing namespace std;\r\n\r\nnamespace nacos{\r\nvoid BeatReactor::start() {\r\n    _stop = false;\r\n    _delayedThreadPool->start();\r\n}\r\n\r\nvoid BeatReactor::stop() {\r\n    if (_stop) {\r\n        log_warn(\"Calling BeatReactor::stop() on an already-stopped BeatReactor\\n\");\r\n        return;\r\n    }\r\n    _stop = true;\r\n    _delayedThreadPool->stop();\r\n}\r\n\r\nvoid BeatReactor::addBeatInfo(const NacosString &serviceName, BeatInfo &beatInfo) {\r\n    NacosString beatInfoStr = beatInfo.toString();\r\n    log_info(\"[BEAT] adding beat: %s to beat map.\\n\", beatInfoStr.c_str());\r\n    NacosString beatKey = buildKey(serviceName, beatInfo.ip, beatInfo.port);\r\n    BeatTask *newBeatTask;\r\n    {\r\n        WriteGuard _lockguard(_beatInfoLock);\r\n        //The specified beatInfo is already in the list\r\n        if (_beatInfoList.count(beatKey) != 0) {\r\n            log_warn(\"Adding already-exist key:%s\\n\", beatKey.c_str());\r\n            return;\r\n        }\r\n        newBeatTask = new BeatTask(beatInfo, _objectConfigData);\r\n        newBeatTask->setScheduled(true);\r\n        newBeatTask->setTaskName(beatKey);\r\n        newBeatTask->setInterval(_clientBeatInterval);\r\n        _beatInfoList[beatKey] = newBeatTask;\r\n    }\r\n    _delayedThreadPool->schedule(newBeatTask, TimeUtils::getCurrentTimeInMs() + _clientBeatInterval);\r\n    //TODO:MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());\r\n}\r\n\r\n/**\r\n* Looks up a beatInfo and return it via beatInfo\r\n* @param serviceName the service name\r\n* @param ip the service's ip\r\n* @param port the service's port\r\n* @param beatInfo the beatInfo, ip and port must be set and cannot be changed via this function\r\n* @return false if beatInfo can't be found with designated serviceName, ip and port\r\n*         true if beatInfo is found\r\n *        the BeatInfo is returned via beatInfo parameter\r\n*/\r\nbool BeatReactor::getBeatInfo(const NacosString &serviceName, const NacosString &ip, int port, BeatInfo &beatInfo) {\r\n    NacosString beatKey = buildKey(serviceName, ip, port);\r\n    {\r\n        ReadGuard _lockguard(_beatInfoLock);\r\n        if (_beatInfoList.count(beatKey) == 0) {\r\n            return false;\r\n        }\r\n\r\n        beatInfo = _beatInfoList[beatKey]->getBeatInfo();\r\n        return true;\r\n    }\r\n}\r\n\r\n/**\r\n* Modifies a beatInfo\r\n* @param serviceName the service name\r\n* @param beatInfo the beatInfo, ip and port must be set and cannot be changed via this function\r\n* @return false if nothing is modified (e.g.: the beatInfo doesn't exist in BeatReactor)\r\n*         true if modification is performed\r\n*/\r\nbool BeatReactor::modifyBeatInfo(const NacosString &serviceName, BeatInfo &beatInfo) {\r\n    NacosString beatInfoStr = beatInfo.toString();\r\n    log_info(\"[BEAT] modify beat: %s to beat map.\\n\", beatInfoStr.c_str());\r\n    NacosString beatKey = buildKey(serviceName, beatInfo.ip, beatInfo.port);\r\n    {\r\n        WriteGuard _lockguard(_beatInfoLock);\r\n        if (_beatInfoList.count(beatKey) != 0) {\r\n            log_warn(\"Modifying non-existent key:%s\\n\", beatKey.c_str());\r\n            return false;\r\n        }\r\n        BeatInfo originalBeatInfo = _beatInfoList[beatKey]->getBeatInfo();\r\n        originalBeatInfo.weight = beatInfo.weight;\r\n        originalBeatInfo.cluster = beatInfo.cluster;\r\n        originalBeatInfo.metadata = beatInfo.metadata;\r\n\r\n        _beatInfoList[beatKey]->setBeatInfo(originalBeatInfo);//modified\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\n/**\r\n* Removes a beatInfo\r\n* @param serviceName the service name\r\n* @param ip the service's ip\r\n* @param port the service's port\r\n* @return false if nothing is removed (e.g.: the beatInfo doesn't exist in BeatReactor)\r\n*         true if a beatInfo is removed\r\n*/\r\nbool BeatReactor::removeBeatInfo(const NacosString &serviceName, const NacosString &ip, int port) {\r\n    log_info(\"[BEAT] removing beat: %s:%s:%d from beat map.\", serviceName.c_str(), ip.c_str(), port);\r\n    NacosString beatKey = buildKey(serviceName, ip, port);\r\n    BeatTask *beatTaskToRemove = NULL;\r\n    {\r\n        WriteGuard _lockguard(_beatInfoLock);\r\n        //If we can't find the beatInfo in the list, just return\r\n        if (_beatInfoList.count(beatKey) != 1) {\r\n            log_warn(\"Removing non-existent key:%s\\n\", beatKey.c_str());\r\n            return false;\r\n        }\r\n        beatTaskToRemove = _beatInfoList[beatKey];\r\n        beatTaskToRemove->setScheduled(false);\r\n        _beatInfoList.erase(beatKey);\r\n    }\r\n    //TODO:MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());\r\n\r\n    return true;\r\n}\r\n\r\nvoid BeatReactor::removeAllBeatInfo() {\r\n    log_debug(\"BeatReactor::removeAllBeatInfo() start to remove\\n\");\r\n    WriteGuard _lockguard(_beatInfoLock);\r\n    for (map<NacosString, BeatTask *>::iterator it = _beatInfoList.begin();\r\n         it != _beatInfoList.end(); it++) {\r\n        BeatTask *curTask = it->second;\r\n        delete curTask;\r\n        curTask = NULL;\r\n    }\r\n    _beatInfoList.clear();\r\n}\r\n\r\nNacosString BeatReactor::buildKey(const NacosString &serviceName, const NacosString &ip, int port) {\r\n    return serviceName + ConfigConstant::NAMING_INSTANCE_ID_SPLITTER\r\n           + ip + ConfigConstant::NAMING_INSTANCE_ID_SPLITTER + NacosStringOps::valueOf(port);\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/naming/beat/BeatReactor.h",
    "content": "#ifndef __BEAT_REACTOR_H_\n#define __BEAT_REACTOR_H_\n\n#include <map>\n#include \"src/naming/NamingProxy.h\"\n#include \"naming/Instance.h\"\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"src/thread/DelayedThreadPool.h\"\n#include \"src/thread/Thread.h\"\n#include \"src/thread/RWLock.h\"\n#include \"BeatTask.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/UtilAndComs.h\"\n#include \"src/factory/ObjectConfigData.h\"\n\nnamespace nacos{\nclass BeatReactor {\nprivate:\n    ObjectConfigData *_objectConfigData;\n    int _threadCount;\n    RWLock _beatInfoLock;\n    std::map<NacosString, BeatTask *> _beatInfoList;\n    volatile uint64_t _clientBeatInterval;\nprotected:\n    friend class BeatTask;\n    volatile bool _stop;\n    DelayedThreadPool *_delayedThreadPool;\npublic:\n    void setClientBeatInterval(uint64_t interval) { _clientBeatInterval = interval; };\n\n    uint64_t getClientBeatInterval() const { return _clientBeatInterval; };\n\n    BeatReactor(ObjectConfigData *objectConfigData, int threadCount)\n            : _objectConfigData(objectConfigData), _beatInfoLock() {\n        _threadCount = threadCount;\n        _stop = true;\n        _clientBeatInterval = 5 * 1000;\n        _delayedThreadPool = new DelayedThreadPool(\"BeatReactor-Daemon\", threadCount);\n    };\n\n    BeatReactor(ObjectConfigData *objectConfigData)\n            : _objectConfigData(objectConfigData), _beatInfoLock() {\n        _threadCount = UtilAndComs::DEFAULT_CLIENT_BEAT_THREAD_COUNT;\n        _stop = true;\n        _clientBeatInterval = 5 * 1000;\n        _delayedThreadPool = new DelayedThreadPool(\"BeatReactor-Daemon\", _threadCount);\n    };\n\n    ~BeatReactor() {\n        log_debug(\"BeatReactor::~BeatReactor() calling stop\\n\");\n        stop();\n        log_debug(\"BeatReactor::~BeatReactor() delete threadpool\\n\");\n        delete _delayedThreadPool;\n        _delayedThreadPool = NULL;\n        log_debug(\"BeatReactor::~BeatReactor() removeAllBeatInfo()\\n\");\n        removeAllBeatInfo();\n    };\n\n    void start();\n\n    void stop();\n\n    void addBeatInfo(const NacosString &serviceName, BeatInfo &beatInfo);\n\n\n    bool modifyBeatInfo(const NacosString &serviceName, BeatInfo &beatInfo);\n\n    bool getBeatInfo(const NacosString &serviceName, const NacosString &ip, int port, BeatInfo &beatInfo);\n\n    bool removeBeatInfo(const NacosString &serviceName, const NacosString &ip, int port);\n\n    //NOTICE:Should be invoked ONLY when the working threads are ALL STOPPED\n    void removeAllBeatInfo();\n\n    NacosString buildKey(const NacosString &serviceName, const NacosString &ip, int port);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/naming/beat/BeatTask.cpp",
    "content": "#include <map>\r\n#include \"BeatReactor.h\"\r\n#include \"NacosString.h\"\r\n\r\nusing namespace std;\r\n\r\nnamespace nacos{\r\nBeatTask::BeatTask(BeatInfo &beatInfo, ObjectConfigData *objectConfigData)\r\n        : _beatInfo(beatInfo), _objectConfigData(objectConfigData), _scheduled(false) {\r\n};\r\n\r\nBeatInfo BeatTask::getBeatInfo() const {\r\n    return _beatInfo;\r\n}\r\n\r\nvoid BeatTask::setBeatInfo(const BeatInfo &beatInfo) {\r\n    _beatInfo = beatInfo;\r\n}\r\n\r\nvoid BeatTask::run() {\r\n    if (!_scheduled) {\r\n        delete this;\r\n        return;\r\n    }\r\n    uint64_t now_ms = TimeUtils::getCurrentTimeInMs();\r\n    _objectConfigData->_beatReactor->_delayedThreadPool->schedule(this, now_ms + _interval);\r\n    _interval = _objectConfigData->_serverProxy->sendBeat(_beatInfo);\r\n}\r\n\r\nBeatTask::~BeatTask() {\r\n    NacosString taskName = getTaskName();\r\n    log_debug(\"[BeatTask]Removing taskObject:%s\\n\", taskName.c_str());\r\n}\r\n}//namespace nacos"
  },
  {
    "path": "src/naming/beat/BeatTask.h",
    "content": "#ifndef __BEAT_TASK_H_\n#define __BEAT_TASK_H_\n\n#include \"BeatInfo.h\"\n#include \"src/naming/NamingProxy.h\"\n#include \"BeatReactor.h\"\n#include \"src/thread/ThreadPool.h\"\n#include \"src/thread/Task.h\"\n#include \"thread/AtomicInt.h\"\n#include \"src/log/Logger.h\"\n#include \"src/factory/ObjectConfigData.h\"\n\nnamespace nacos{\nclass BeatReactor;\n\nclass BeatTask : public Task {\nprivate:\n    BeatInfo _beatInfo;\n    ObjectConfigData *_objectConfigData;\n    bool _scheduled;\n    uint64_t _interval;//interval for heartbeat got from the server\npublic:\n    BeatTask(BeatInfo &beatInfo, ObjectConfigData *objectConfigData);\n\n    ~BeatTask();\n\n    void setBeatInfo(const BeatInfo &beatInfo);\n    BeatInfo getBeatInfo() const;\n\n    void run();\n\n    void setScheduled(bool scheduled) { _scheduled = scheduled; };\n    bool getScheduled() { return _scheduled; };\n\n    void setInterval(uint64_t interval) { _interval = interval; };\n    uint64_t getInterval() const { return _interval; };\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/naming/cache/ChangeAdvice.cpp",
    "content": "#include \"naming/ChangeAdvice.h\"\n\nusing namespace std;\n\nnamespace nacos{\nChangeAdvice::ChangeAdvice()\n{\n    added = false;\n    modified = false;\n    removed = false;\n    //addedInstances.clear();\n    //removedInstances.clear();\n    //modifiedInstances.clear();\n}\n\nChangeAdvice::~ChangeAdvice()\n{\n}\n\nvoid ChangeAdvice::compareChange\n(\n        ServiceInfo &oldInfo,\n        ServiceInfo &newInfo,\n        ChangeAdvice &changeAdvice\n)\n{\n    map<NacosString, Instance> oldInstanceList;\n    map<NacosString, Instance> newInstanceList;\n    for (list<Instance>::iterator it = oldInfo.getHostsNocopy()->begin();\n        it != oldInfo.getHostsNocopy()->end(); it++)\n    {\n        oldInstanceList[it->toInetAddr()] = *it;\n    }\n\n    for (list<Instance>::iterator it = newInfo.getHostsNocopy()->begin();\n         it != newInfo.getHostsNocopy()->end(); it++)\n    {\n        newInstanceList[it->toInetAddr()] = *it;\n    }\n\n    //find removed instances\n    for (map<NacosString, Instance>::iterator it = oldInstanceList.begin();\n        it != oldInstanceList.end(); it++)\n    {\n        if (newInstanceList.count(it->first) == 0)\n        {\n            changeAdvice.removed = true;\n            //changeAdvice.removedInstances.push_back(it->second);\n        }\n        else//find modified instances\n        {\n            //the item exists in both Lists, compare the content between these 2\n            if (it->second != newInstanceList[it->first])\n            {\n                changeAdvice.modified = true;\n                //changeAdvice.modifiedInstances.push_back(newInstanceList[it->first]);\n            }\n\n        }\n    }\n\n    //find added instances\n    for (map<NacosString, Instance>::iterator it = newInstanceList.begin();\n         it != newInstanceList.end(); it++)\n    {\n        if (oldInstanceList.count(it->first) == 0)\n        {\n            changeAdvice.added = true;\n            //changeAdvice.addedInstances.push_back(it->second);\n        }\n    }\n}\n\nNacosString ChangeAdvice::toString()\n{\n    return \"Unimplemented\";//trivial function\n}\n}//namespace nacos"
  },
  {
    "path": "src/naming/cache/NamingCache.cpp",
    "content": "#include \"NamingCache.h\"\n\nnamespace nacos{\nServiceInfo NamingCache::getServiceInfo(const NacosString &key) NACOS_THROW(NacosException)\n{\n    ReadGuard __readGuard(_rwLock);\n    if (!contains(key))\n    {\n        throw NacosException(0, \"Key\" + key + \" doesn't exist\");\n    }\n    return namingList[key];\n}\n\nbool NamingCache::contains(const NacosString &key)\n{\n    ReadGuard __readGuard(_rwLock);\n    return namingList.count(key) > 0;\n}\n\nvoid NamingCache::setServiceInfo(const NacosString &key, const ServiceInfo &info)\n{\n    WriteGuard __writeGuard(_rwLock);\n    if (_eventDispatcher != NULL)\n    {\n        ChangeAdvice changeAdvice;\n        if (namingList.count(key) > 0)\n        {\n            //changeAdvice.oldServiceInfo = namingList[key];\n            //changeAdvice.newServiceInfo = info;\n        }\n        else\n        {\n            //changeAdvice.newServiceInfo = info;\n        }\n        //_eventDispatcher->notify(changeAdvice);\n    }\n    namingList[key] = info;\n}\n\nvoid NamingCache::removeServiceInfo(const NacosString &key)\n{\n    WriteGuard __writeGuard(_rwLock);\n    if (namingList.count(key) == 0)\n    {\n        return;\n    }\n    if (_eventDispatcher != NULL)\n    {\n        ChangeAdvice changeAdvice;\n        //changeAdvice.oldServiceInfo = namingList[key];\n        //_eventDispatcher->notify(changeAdvice);\n    }\n    namingList.erase(key);\n}\n}//namespace nacos\n"
  },
  {
    "path": "src/naming/cache/NamingCache.h",
    "content": "#ifndef __NAMING_CACHE_H_\n#define __NAMING_CACHE_H_\n\n#include <map>\n#include \"NacosString.h\"\n#include \"src/naming/subscribe/EventDispatcher.h\"\n#include \"naming/ServiceInfo.h\"\n#include \"src/thread/RWLock.h\"\n#include \"naming/ChangeAdvice.h\"\n#include \"Compatibility.h\"\n#include \"NacosExceptions.h\"\n\nnamespace nacos{\nclass NamingCache {\nprivate:\n    std::map<NacosString, ServiceInfo> namingList;\n    RWLock _rwLock;\n    EventDispatcher *_eventDispatcher;\npublic:\n    NamingCache();\n    NamingCache(EventDispatcher *eventDispatcher) { _eventDispatcher = eventDispatcher; };\n    ServiceInfo getServiceInfo(const NacosString &key) NACOS_THROW(NacosException);\n    bool contains(const NacosString &key);\n    void setServiceInfo(const NacosString &key, const ServiceInfo &info);\n    void removeServiceInfo(const NacosString &key);\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/naming/selectors/HealthInstanceSelector.cpp",
    "content": "#include <list>\n#include \"naming/selectors/HealthInstanceSelector.h\"\n\nnamespace nacos { namespace naming { namespace selectors {\n\nstd::list<nacos::Instance> HealthInstanceSelector::select(const std::list<nacos::Instance> &instancesToSelect){\n    std::list<nacos::Instance> result;\n    for (std::list<nacos::Instance>::const_iterator it = instancesToSelect.begin();\n         it != instancesToSelect.end(); it++) {\n        if (it->healthy) {\n            result.push_back(*it);\n        }\n    }\n\n    return result;\n}\n\n} /*selectors*/ } /*naming*/ }/*nacos*/\n"
  },
  {
    "path": "src/naming/selectors/RandomByWeightSelector.cpp",
    "content": "#include <list>\n#include <vector>\n#include \"naming/selectors/RandomByWeightSelector.h\"\n#include \"src/log/Logger.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"src/utils/RandomUtils.h\"\n\n#define BASIC_WEIGHT 65536\n\nnamespace nacos { namespace naming { namespace selectors {\n\nstd::list<Instance> RandomByWeightSelector::select(const std::list<Instance> &instancesToSelect){\n    std::vector<std::pair<int, std::list<Instance>::const_iterator > > weightedList;\n    std::list<Instance> result;\n\n    int total_weight = 0;\n    for (std::list<Instance>::const_iterator it = instancesToSelect.begin();\n         it != instancesToSelect.end(); it++) {\n        if (it->weight < 1e-10) {\n            //we consider a very small weight as 0\n            continue;\n        }\n        total_weight += it->weight * BASIC_WEIGHT;\n        log_debug(\"RandomByWeightSelector::select:weight for current instance:%f\\n\", it->weight);\n        weightedList.push_back(std::make_pair(it->weight * BASIC_WEIGHT, it));\n    }\n    if (total_weight == 0) {\n        //no server instance is chosen\n        return result;\n    }\n    log_debug(\"RandomByWeightSelector::select:total_weight:%d\\n\", total_weight);\n    size_t selectedWeight = RandomUtils::random(0, total_weight - 1);\n    log_debug(\"RandomByWeightSelector::select selected weight:%d\\n\", selectedWeight);\n\n    std::vector<std::pair<int, std::list<Instance>::const_iterator> >::const_iterator it = weightedList.begin();\n    while (selectedWeight > it->second->weight * BASIC_WEIGHT) {\n        selectedWeight -= it->second->weight * BASIC_WEIGHT;\n        it++;\n    }\n\n    result.push_back(*it->second);\n    return result;\n}\n\n} /*selectors*/ } /*naming*/ }/*nacos*/"
  },
  {
    "path": "src/naming/selectors/RandomSelector.cpp",
    "content": "#include \"naming/selectors/RandomSelector.h\"\n#include \"src/log/Logger.h\"\n#include \"src/utils/RandomUtils.h\"\n#include \"src/utils/ParamUtils.h\"\n\nnamespace nacos { namespace naming { namespace selectors {\n\nstd::list<Instance> RandomSelector::select(const std::list<Instance> &instancesToSelect){\n    size_t maxSvrSlot = instancesToSelect.size();\n    log_debug(\"RandomSelector::select:nr_servers%d\\n\", maxSvrSlot);\n    size_t selectedServer;\n    if (maxSvrSlot == 1) {\n        selectedServer = 0;\n    } else {\n        selectedServer = RandomUtils::random(0, maxSvrSlot - 1);\n    }\n    log_debug(\"RandomSelector::select:%d\\n\", selectedServer);\n\n    std::list<Instance> result;\n\n    result.push_back(ParamUtils::getNthElem(instancesToSelect, selectedServer));\n\n    return result;\n}\n\n} /*selectors*/ } /*naming*/ }/*nacos*/"
  },
  {
    "path": "src/naming/subscribe/EventDispatcher.cpp",
    "content": "//\n// Created by liuhanyu on 2020/9/25.\n//\n\n#include \"EventDispatcher.h\"\n#include \"src/debug/DebugAssertion.h\"\n\nusing namespace std;\n\nnamespace nacos{\nbool EventDispatcher::addListener(const NacosString &serviceName, const NacosString &clusters, EventListener *eventListener)\n{\n    NACOS_ASSERT(eventListener != NULL);\n    WriteGuard __writeGuard(rwLock);\n    NacosString key = ServiceInfo::getKey(serviceName, clusters);\n    if (observerMap.count(key) > 0)\n    {\n        list<EventListener*> &listenerList = observerMap[key];\n        for (list<EventListener*>::iterator it = listenerList.begin();\n            it != listenerList.end(); it++)\n        {\n            if ((*it) == eventListener)\n            {\n                return false;\n            }\n        }\n        eventListener->incRef();\n        listenerList.push_back(eventListener);\n        return true;\n    }\n    else\n    {\n        list<EventListener*> listenerList;\n        eventListener->incRef();\n        listenerList.push_back(eventListener);\n        observerMap[key] = listenerList;\n        return true;\n    }\n}\n\nbool EventDispatcher::removeListenerHelper(const NacosString &key, EventListener *eventListener, int &remainingListeners)\n{\n    list<EventListener*> &listenerList = observerMap[key];\n    for (list<EventListener*>::iterator it = listenerList.begin();\n         it != listenerList.end(); it++) {\n        if (*it == eventListener) {\n            EventListener *removedItem = *it;\n            log_debug(\"[EventDispatcher]-remove:erased item: %s\\n\", removedItem->getListenerName().c_str());\n            listenerList.erase(it);\n\n            int refCount = removedItem->decRef();\n            if (refCount == 0) {\n                log_debug(\"[EventDispatcher]-remove:The refcount of listener '%s' is 0, deleting the item.\\n\", removedItem->getListenerName().c_str());\n                delete removedItem;\n            }\n            if (listenerList.empty()) {\n                observerMap.erase(key);\n            }\n            remainingListeners = listenerList.size();\n            return true;\n        }\n    }\n    return false;\n}\n\nbool EventDispatcher::removeListener(const NacosString &serviceName, const NacosString &clusters, EventListener *eventListener, int &remainingListeners)\n{\n    NACOS_ASSERT(eventListener != NULL);\n    WriteGuard __writeGuard(rwLock);\n    NacosString key = ServiceInfo::getKey(serviceName, clusters);\n    if (observerMap.count(key) == 0) {\n        remainingListeners = 0;\n        return false;\n    }\n    else\n    {\n        return removeListenerHelper(key, eventListener, remainingListeners);\n    }\n}\n\nvoid EventDispatcher::start()\n{\n    if (_started) {\n        return;\n    }\n    _started = true;\n    eventNotifier->start();\n}\n\nvoid EventDispatcher::stop()\n{\n    if (!_started) {\n        log_debug(\"[EventDispatcher]:Calling stop() on a already-stopped EventDispatcher\\n\");\n        return;\n    }\n    _started = false;\n    NotifyData notifyData;\n    notifyData.exit = true;\n    notifyDataList.enqueue(notifyData);\n}\n\nvoid EventDispatcher::notify(const ChangeAdvice &changeAdvice)\n{\n    NacosString key = changeAdvice.key;\n\n    NotifyData notifyData;\n    {\n        ReadGuard __readGuard(rwLock);\n        if (observerMap.count(key) == 0)\n        {\n            log_debug(\"[EventDispatcher]:Notifying non-existent key:%s\\n\", key.c_str());\n            return;\n        }\n        list<EventListener*> &listeners = observerMap[key];\n        for (list<EventListener *>::iterator it = listeners.begin();\n            it != listeners.end(); it++) {\n            (*it)->incRef();\n        }\n        notifyData.listeners = listeners;\n    }\n    notifyData.serviceInfo = changeAdvice.newServiceInfo;\n    notifyDataList.enqueue(notifyData);\n}\n\nvoid EventDispatcher::notifyDirectly(const ChangeAdvice &changeAdvice)\n{\n    NacosString key = changeAdvice.key;\n\n    list<EventListener*> listeners;\n    {\n        ReadGuard __readGuard(rwLock);\n        if (observerMap.count(key) == 0)\n        {\n            log_debug(\"[EventDispatcher]:Notifying non-existent key:%s\\n\", key.c_str());\n            return;\n        }\n        listeners = observerMap[key];\n        for (list<EventListener*>::iterator it = listeners.begin();\n            it != listeners.end(); it++) {\n            (*it)->incRef();\n        }\n    }\n\n    for (list<EventListener*>::iterator curListener = listeners.begin();\n        curListener != listeners.end(); curListener++)\n    {\n        //asm volatile(\"int $3\");\n        (*curListener)->receiveNamingInfo(changeAdvice.newServiceInfo);\n        int refCnt = (*curListener)->decRef();\n        if (refCnt == 0) {\n            log_debug(\"[EventDispatcher]:Destroying listener whose refcount = 0\\n\");\n            delete *curListener;\n        }\n    }\n}\n\nvoid *EventDispatcher::eventDispatcherThread(void *parm)\n{\n    EventDispatcher *thisObj = (EventDispatcher*)parm;\n\n    while (true) {\n        NotifyData notifyData = thisObj->notifyDataList.dequeue();\n\n        if (notifyData.exit) {\n            while (!thisObj->notifyDataList.empty()) {\n                NotifyData notifyDataToRemove = thisObj->notifyDataList.dequeue();\n                for (list<EventListener*>::iterator curListener = notifyDataToRemove.listeners.begin();\n                curListener != notifyDataToRemove.listeners.end(); curListener++) {\n                    (*curListener)->decRef();\n                    int refCount = (*curListener)->decRef();\n                    if (refCount == 0) {\n                        delete (*curListener);\n                    }\n                }\n            }\n            return 0;\n        }\n\n        for (list<EventListener*>::iterator curListener = notifyData.listeners.begin();\n            curListener != notifyData.listeners.end(); curListener++) {\n            (*curListener)->receiveNamingInfo(notifyData.serviceInfo);\n            (*curListener)->decRef();\n            int refCount = (*curListener)->decRef();\n            if (refCount == 0) {\n                delete (*curListener);\n            }\n        }\n    }\n\n    return 0;\n}\n\n//NOTE:This function can be called ONLY when the dispatcher thread is stopped!\n//This designed to be called when the an EventDispatcher Object is dtor'd\nvoid EventDispatcher::purgeAllListeners()\n{\n    WriteGuard __writeGuard(rwLock);\n\n    for (map<NacosString, list<EventListener*> >::iterator it = observerMap.begin();\n            it != observerMap.end(); it++) {\n\n        for (list<EventListener*>::iterator listenerItem = it->second.begin();\n            listenerItem != it->second.end(); listenerItem++) {\n            int refCount = (*listenerItem)->decRef();\n            if (refCount == 0)\n            {\n                log_debug(\"[EventDispatcher]:Deleting the object whose refcount = 0:%s\\n\", (*listenerItem)->getListenerName().c_str());\n                delete *listenerItem;\n                *listenerItem = NULL;\n            }\n        }\n    }\n\n    for (map<NacosString, list<EventListener*> >::iterator it = observerMap.begin();\n         it != observerMap.end(); it++) {\n        for (list<EventListener*>::iterator curListener = it->second.begin();\n            curListener != it->second.end(); curListener++)\n        {\n            NACOS_ASSERT(*curListener == NULL);\n        }\n    }\n\n    observerMap.clear();\n}\n\nEventDispatcher::EventDispatcher()\n{\n    _started = false;\n    eventNotifier = new Thread(\"Nacos-NamingEvent-Dispatcher\", eventDispatcherThread, (void*)this);\n}\n\nEventDispatcher::~EventDispatcher()\n{\n    stop();\n    eventNotifier->join();\n    delete eventNotifier;\n    eventNotifier = NULL;\n    purgeAllListeners();\n}\n}//namespace nacos"
  },
  {
    "path": "src/naming/subscribe/EventDispatcher.h",
    "content": "#ifndef __EVT_DISPTCH_H_\n#define __EVT_DISPTCH_H_\n\n#include \"src/thread/Thread.h\"\n#include \"src/thread/RWLock.h\"\n#include \"src/thread/BlockingQueue.h\"\n#include \"naming/subscribe/EventListener.h\"\n#include <map>\n\nnamespace nacos{\nstruct NotifyData\n{\n    NotifyData() { exit = false; };\n    bool exit;\n    ServiceInfo serviceInfo;\n    std::list<EventListener *> listeners;\n};\n\n//TODO:refactor to 2 types of eventDispatcher:\n//1. blocking mode, notify in notifier's thread\n//2. non-blocking mode(async), dispatcher has a blocking queue and send notify in that thread asynchronously\nclass EventDispatcher {\nprivate:\n    volatile bool _started;\n    RWLock rwLock;//for observerMap\n    std::map<NacosString, std::list<EventListener*> > observerMap;\n    BlockingQueue<NotifyData> notifyDataList;\n    Thread *eventNotifier;\n\n    static void *eventDispatcherThread(void *parm);\n\n    bool removeListenerHelper(const NacosString &key, EventListener *eventListener, int &remainingListeners);\n\n    void purgeAllListeners();\npublic:\n    bool addListener(const NacosString &serviceName, const NacosString &clusters, EventListener *eventListener);\n    bool removeListener(const NacosString &serviceName, const NacosString &clusters, EventListener *eventListener, int &remainingListeners);\n    void notify(const ChangeAdvice &changeAdvice);\n    void notifyDirectly(const ChangeAdvice &changeAdvice);\n    void stop();\n    void start();\n    EventDispatcher();\n    ~EventDispatcher();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/naming/subscribe/EventListener.cpp",
    "content": "#include \"naming/subscribe/EventListener.h\"\n#include \"src/debug/DebugAssertion.h\"\n\nnamespace nacos {\n\nEventListener::~EventListener() {\n    NACOS_ASSERT(refCnt() == 0)\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/naming/subscribe/HostReactor.cpp",
    "content": "//\n// Created by liuhanyu on 2021/1/7.\n//\n\n#include \"HostReactor.h\"\n#include \"src/json/JSON.h\"\n#include \"src/utils/NamingUtils.h\"\n#include \"src/naming/subscribe/EventDispatcher.h\"\n\nnamespace nacos {\n\nHostReactor::HostReactor(ObjectConfigData *objectConfigData) {\n    _objectConfigData = objectConfigData;\n}\n\nvoid HostReactor::processServiceJson(const NacosString &json) {\n    ServiceInfo serviceInfo = JSON::JsonStr2ServiceInfo(json);\n\n    NacosString name = NamingUtils::getGroupedName(serviceInfo.getName(), serviceInfo.getGroupName());\n    NacosString key = ServiceInfo::getKey(name, serviceInfo.getClusters());\n    ServiceInfo oldServiceInfo;\n    bool newServiceInfo = false;\n    {\n        WriteGuard _writeGuard(rwLock);\n        if (serviceInfoMap.count(key) == 0) {\n            if (serviceInfo.ipCount()==0) {\n                log_warn(\"hosts got from server is empty.\\n\");\n                return;\n            }\n            serviceInfoMap[key] = serviceInfo;\n            newServiceInfo = true;\n        } else {\n            oldServiceInfo = serviceInfoMap[key];\n            if (oldServiceInfo.getLastRefTime() >= serviceInfo.getLastRefTime()) {\n                log_warn(\"ServiceInfo got from server is older than the one in client.\\n\");\n                return;\n            }\n            serviceInfoMap[key] = serviceInfo;//update local service info to the new one\n        }\n    }\n    ChangeAdvice changeAdvice;\n    changeAdvice.key = key;\n    if (newServiceInfo) {\n        changeAdvice.added = true;\n        changeAdvice.newServiceInfo = serviceInfo;\n        _objectConfigData->_eventDispatcher->notifyDirectly(changeAdvice);\n    } else {//service info is updated\n        ChangeAdvice::compareChange(oldServiceInfo, serviceInfo, changeAdvice);\n        log_debug(\"Change status:modified:%d added:%d removed:%d\\n\", changeAdvice.modified, changeAdvice.added,\n                  changeAdvice.removed);\n        if (changeAdvice.modified || changeAdvice.added || changeAdvice.removed) {\n            //asm volatile(\"int $3\");\n            changeAdvice.newServiceInfo = serviceInfo;\n            _objectConfigData->_eventDispatcher->notifyDirectly(changeAdvice);\n        }\n    }\n}\n\n}"
  },
  {
    "path": "src/naming/subscribe/HostReactor.h",
    "content": "//\n// Created by liuhanyu on 2021/1/7.\n//\n\n#ifndef NACOS_SDK_CPP_HOSTREACTOR_H\n#define NACOS_SDK_CPP_HOSTREACTOR_H\n#include <map>\n#include \"NacosString.h\"\n#include \"naming/ServiceInfo.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"src/thread/RWLock.h\"\n\nnamespace nacos {\n\nclass HostReactor {\nprivate:\n    ObjectConfigData *_objectConfigData;\n    //memory cache\n    std::map<NacosString, ServiceInfo> serviceInfoMap;\n    //rw lock for serviceInfoMap\n    RWLock rwLock;\npublic:\n    HostReactor(ObjectConfigData *objectConfigData);\n    void processServiceJson(const NacosString &json);\n};\n\n}\n\n#endif //NACOS_SDK_CPP_HOSTREACTOR_H\n"
  },
  {
    "path": "src/naming/subscribe/SubscriptionPoller.cpp",
    "content": "#include \"SubscriptionPoller.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"src/utils/NamingUtils.h\"\n#include \"src/json/JSON.h\"\n#include \"HostReactor.h\"\n\nusing namespace std;\n\nnamespace nacos{\nSubscriptionPoller::SubscriptionPoller(ObjectConfigData *objectConfigData)\n{\n    _objectConfigData = objectConfigData;\n    _pollingThread = new Thread(\"NamingServicePoller\", pollingThreadFunc, (void*)this);\n    _pollingInterval = atoi(_objectConfigData->_appConfigManager->get(PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL).c_str());\n    _udpPort = atoi(_objectConfigData->_appConfigManager->get(PropertyKeyConst::UDP_RECEIVER_PORT).c_str());\n    _started = false;\n}\n\nSubscriptionPoller::~SubscriptionPoller()\n{\n    if (_started) {\n        stop();\n    }\n    if (_pollingThread != NULL)\n    {\n        delete _pollingThread;\n        _pollingThread = NULL;\n    }\n}\n\nbool SubscriptionPoller::addPollItem(const NacosString &serviceName, const NacosString &groupName, const NacosString &clusters)\n{\n    struct PollingData pd;\n    pd.clusters = clusters;\n    pd.serviceName = serviceName;\n    pd.groupName = groupName;\n    NacosString name = NamingUtils::getGroupedName(serviceName, groupName);\n    NacosString key = ServiceInfo::getKey(name, clusters);\n\n    {\n        WriteGuard __writeGuard(rwLock);\n        if (pollingList.count(key) > 0) {\n            return false;\n        }\n        pollingList[key] = pd;\n        return true;\n    }\n}\n\nbool SubscriptionPoller::removePollItem(const NacosString &serviceName, const NacosString &groupName, const NacosString &clusters)\n{\n    NacosString name = NamingUtils::getGroupedName(serviceName, groupName);\n    NacosString key = ServiceInfo::getKey(name, clusters);\n    {\n        WriteGuard __writeGuard(rwLock);\n        if (pollingList.count(key) == 0) {\n            return false;\n        }\n        pollingList.erase(key);\n    }\n    return true;\n}\n\nvoid SubscriptionPoller::start()\n{\n    if (_started) {\n        log_warn(\"Calling start on already-started SubscriptionPoller\\n\");\n        return;\n    }\n    _started = true;\n    _pollingThread->start();\n}\n\nvoid SubscriptionPoller::stop()\n{\n    if (!_started) {\n        log_warn(\"Calling stop on already-stopped SubscriptionPoller\\n\");\n        return;\n    }\n\n    _started = false;\n    _pollingThread->kill();\n    _pollingThread->join();\n}\n\nvoid *SubscriptionPoller::pollingThreadFunc(void *parm)\n{\n    SubscriptionPoller *thisObj = (SubscriptionPoller*)parm;\n    while (thisObj->_started) {\n        log_debug(\"SubscriptionPoller::pollingThreadFunc start polling, interval = %d\\n\", thisObj->_pollingInterval);\n        map<NacosString, PollingData> copiedList;\n        {\n            ReadGuard __readGuard(thisObj->rwLock);\n            copiedList = thisObj->pollingList;\n            log_debug(\"Copied polling list, size = %d\\n\", copiedList.size());\n        }\n        if (copiedList.empty()) {\n            log_debug(\"PollingList is empty, hibernating...\\n\", copiedList.size());\n            sleep(thisObj->_pollingInterval / 1000);\n            continue;\n        }\n\n        for (map<NacosString, PollingData>::iterator it = copiedList.begin();\n             it != copiedList.end(); it++) {\n            NacosString name = NamingUtils::getGroupedName(it->second.serviceName, it->second.groupName);\n            NacosString key = ServiceInfo::getKey(name, it->second.clusters);\n            log_debug(\"Polling data: name=%s, key=%s\\n\", name.c_str(), key.c_str());\n\n            NacosString result;\n            try {\n                result = thisObj->_objectConfigData->_serverProxy->queryList(\n                        it->second.serviceName, it->second.groupName, it->second.clusters, thisObj->_udpPort,false);\n            }\n            catch (NacosException &e) {\n                //no server available or all servers tried but failed\n                //just ignore and wait the network restore or manual restore\n                //the reason why we choose to ignore the exception is that:\n                //1. the network is down, we don't know the current status of the server, so we don't know whether it changed or not\n                //for that reason we can't make any notifications\n                //2. when the network restored, we can get the latest status of the server and send notifications\n                //3. if the network is down for a rather long time, manual restore is needed,\n                //and the server will be restarted, this listener thread will be restarted, too\n                //4. when the server returns a 404 error, we still need to poll the service's information, since it may become available sometime later\n                continue;\n            }\n\n            log_debug(\"Server info got from server:%s\\n=======>\\n\", result.c_str());\n\n            thisObj->_objectConfigData->_hostReactor->processServiceJson(result);\n        }\n\n        log_debug(\"Polling process finished, hibernating...\\n\");\n        sleep(thisObj->_pollingInterval / 1000);\n    }\n    log_debug(\"Polling thread for NamingService exited normally.\\n\");\n    return NULL;\n}\n}//namespace nacos\n"
  },
  {
    "path": "src/naming/subscribe/SubscriptionPoller.h",
    "content": "//\n// Created by liuhanyu on 2020/9/26.\n//\n\n#ifndef NACOS_SDK_CPP_SUBSCRIPTIONPOLLER_H\n#define NACOS_SDK_CPP_SUBSCRIPTIONPOLLER_H\n\n#include <map>\n#include \"src/thread/Thread.h\"\n#include \"src/naming/NamingProxy.h\"\n#include \"EventDispatcher.h\"\n#include \"src/factory/ObjectConfigData.h\"\n\nnamespace nacos{\nstruct PollingData\n{\n    NacosString serviceName;\n    NacosString groupName;\n    NacosString clusters;\n    volatile long nextPollTime;\n};\n\nclass SubscriptionPoller\n{\nprivate:\n    Thread *_pollingThread;\n    int _pollingInterval;//In ms\n    int _udpPort;//udp receiver port\n    volatile bool _started;\n    ObjectConfigData *_objectConfigData;\n\n    SubscriptionPoller();\n\n    static void *pollingThreadFunc(void *parm);\n\n    //for polling list\n    RWLock rwLock;\n    std::map<NacosString, PollingData> pollingList;\npublic:\n    SubscriptionPoller(ObjectConfigData *objectConfigData);\n    bool addPollItem(const NacosString &serviceName, const NacosString &groupName, const NacosString &clusters);\n    bool removePollItem(const NacosString &serviceName, const NacosString &groupName, const NacosString &clusters);\n    void start();\n    void stop();\n    ~SubscriptionPoller();\n\n};\n}//namespace nacos\n\n#endif //NACOS_SDK_CPP_SUBSCRIPTIONPOLLER_H\n"
  },
  {
    "path": "src/naming/subscribe/UdpNamingServiceListener.cpp",
    "content": "#include <errno.h>\n#include <string.h>\n#include <unistd.h>\n\n#include \"UdpNamingServiceListener.h\"\n#include \"src/config/AppConfigManager.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/json/JSON.h\"\n#include \"HostReactor.h\"\n#include \"zlib.h\"\n#include \"src/debug/DebugAssertion.h\"\n\n#include <iostream>\nusing namespace std;\n\nnamespace nacos {\n\nvoid UdpNamingServiceListener::initializeUdpListener() NACOS_THROW(NacosException) {\n    log_debug(\"in thread UdpNamingServiceListener::initializeUdpListener()\\n\");\n    // Creating socket file descriptor\n    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {\n        throw NacosException(NacosException::UNABLE_TO_CREATE_SOCKET, \"Unable to create socket\");\n    }\n\n    memset(&cliaddr, 0, sizeof(cliaddr));\n\n    // Filling client information\n    cliaddr.sin_family = AF_INET; // IPv4\n    cliaddr.sin_addr.s_addr = INADDR_ANY;\n    cliaddr.sin_port = htons(udpReceiverPort);\n    log_debug(\"udp receiver port = %d\\n\", cliaddr.sin_port);\n\n    // Bind the socket with the server address\n    if ( ::bind(sockfd, (const struct sockaddr *)&cliaddr,\n              sizeof(cliaddr)) < 0 )\n    {\n        throw NacosException(NacosException::UNABLE_TO_CREATE_SOCKET, \"Unable to bind\");\n    }\n\n    log_debug(\"socket bound\\n\");\n}\n\nbool UdpNamingServiceListener::unGzip(char *inBuffer, size_t inSize) {\n    //reference:https://zlib.net/zlib_how.html\n    /* allocate inflate state */\n    z_stream strm;\n    strm.zalloc = Z_NULL;\n    strm.zfree = Z_NULL;\n    strm.opaque = Z_NULL;\n    strm.avail_in = 0;\n    strm.next_in = Z_NULL;\n    int ret = inflateInit2(&strm, MAX_WBITS + 16);\n    if (ret != Z_OK) {\n        log_error(\"failed to perform inflateInit()\\n\");\n        return false;\n    }\n\n    strm.avail_in = inSize;\n    strm.next_in = (unsigned char*)inBuffer;\n    strm.avail_out = sizeof(this->uncompressedData);\n    strm.next_out = (unsigned char*)this->uncompressedData;\n    ret = inflate(&strm, Z_NO_FLUSH);\n    NACOS_ASSERT(ret != Z_STREAM_ERROR);\n    switch (ret) {\n    case Z_NEED_DICT:\n        ret = Z_DATA_ERROR;     /* and fall through */\n    case Z_DATA_ERROR:\n    case Z_MEM_ERROR:\n        (void)inflateEnd(&strm);\n        log_error(\"in switch block, inflate failed with code = %d\\n\", ret);\n        return false;\n    }\n    \n    if (strm.avail_out == 0) {\n        log_error(\"uncompressed data exceeds the size limit, please consider a larger uncompressedData\\n\");\n        return false;\n    }\n\n    (void)inflateEnd(&strm);\n\n    this->uncompressedData[sizeof(this->uncompressedData) - strm.avail_out] = '\\0';\n    return true;\n}\n\nvoid *UdpNamingServiceListener::listenerThreadFunc(void *param) {\n    UdpNamingServiceListener *thisObj = (UdpNamingServiceListener*)param;\n    log_debug(\"in thread UdpNamingServiceListener::listenerThreadFunc()\\n\");\n    thisObj->initializeUdpListener();\n    while (thisObj->_started) {\n        int ret;//also data_len\n\n        log_debug(\"before recvfrom() socketfd:%d\\n\", thisObj->sockfd);\n        struct sockaddr src_addr = {0};\n        socklen_t src_addr_len = sizeof(struct sockaddr_in);\n        ret = recvfrom(thisObj->sockfd, (char *)thisObj->receiveBuffer, UDP_MSS, MSG_WAITALL, &src_addr, &src_addr_len);\n        log_debug(\"ret got from recvfrom():%d\\n\", ret);\n\n        if (ret == -1) {\n            if (errno == EINTR) {\n                log_debug(\"got sigint from main thread, exiting...\\n\");\n                //got kill() signal from main thread, free resources & exit\n            }\n            //other kinds of error\n            break;\n        }\n        //parse the package\n        thisObj->receiveBuffer[ret] = 0;\n        log_debug(\"content got from UDP server is %s\\n\", thisObj->receiveBuffer);\n        PushPacket pushPacket;\n\n        try {\n            if (ret <= 2) {\n                //the server returns a packet shorter than 2 bytes, which could not be parsed by the listener\n                log_warn(\"got an invalid packet, len = %d, content = %s\", ret, thisObj->receiveBuffer);\n                continue;\n            }\n            char *packetToParse = thisObj->receiveBuffer;\n            if ((unsigned char)thisObj->receiveBuffer[0] == 0x1f && (unsigned char)thisObj->receiveBuffer[1] == 0x8b) {\n                if (!thisObj->unGzip(thisObj->receiveBuffer, ret)) {\n                    continue;\n                }\n                packetToParse = thisObj->uncompressedData;\n            }\n            pushPacket = JSON::Json2PushPacket(packetToParse);\n        } catch (NacosException &e) {\n            log_error(\"Invalid json string got from server:%s\\n\", thisObj->receiveBuffer);\n            continue;\n        }\n\n        NacosString ack;\n\n        if (pushPacket.type == \"dom\" || pushPacket.type == \"service\") {\n            thisObj->_objectConfigData->_hostReactor->processServiceJson(pushPacket.data);\n\n            // send ack to server\n            ack = \"{\\\"type\\\": \\\"push-ack\\\", \\\"lastRefTime\\\":\\\"\" + NacosStringOps::valueOf(pushPacket.lastRefTime) + \"\\\", \\\"data\\\":\\\"\\\"}\";\n        } else if (pushPacket.type == \"dump\") {\n            // dump data to server\n            //TODO:Unimplemented\n            ack = \"{\\\"type\\\": \\\"dump-ack\\\", \\\"lastRefTime\\\": \\\"\" + NacosStringOps::valueOf(pushPacket.lastRefTime) + \"\\\", \\\"data\\\":\\\"\\\"}\";\n        } else {\n            // do nothing & send ack only\n            ack = \"{\\\"type\\\": \\\"unknown-ack\\\", \\\"lastRefTime\\\":\\\"\" + NacosStringOps::valueOf(pushPacket.lastRefTime)\n                  + \"\\\", \\\"data\\\":\\\"\\\"}\";\n        }\n\n        ssize_t recv_ret = sendto(thisObj->sockfd, ack.c_str(), ack.length(), 0, &src_addr, src_addr_len);\n        if (recv_ret < 0) {\n            log_error(\"error while sending data...%d\\n\", errno);\n        }\n    }\n\n    close(thisObj->sockfd);\n    return NULL;\n}\n\nUdpNamingServiceListener::UdpNamingServiceListener(ObjectConfigData *objectConfigData) {\n    _listenerThread = NULL;\n    _started = false;\n    _objectConfigData = objectConfigData;\n    udpReceiverPort = atoi(_objectConfigData->_appConfigManager->get(PropertyKeyConst::UDP_RECEIVER_PORT).c_str());\n    log_debug(\"udpReceiverPort is %d\\n\", udpReceiverPort);\n    _listenerThread = new Thread(objectConfigData->name + \"UDPListener\", listenerThreadFunc, (void*)this);\n}\n\nvoid UdpNamingServiceListener::start() {\n    if (_started) {\n        return;\n    }\n\n    _started = true;\n    _listenerThread->start();\n}\n\nvoid UdpNamingServiceListener::stop() {\n    if (!_started) {\n        return;\n    }\n\n    _started = false;\n    _listenerThread->kill();\n    _listenerThread->join();\n}\n\nUdpNamingServiceListener::~UdpNamingServiceListener() {\n    if (_started) {\n        stop();\n    }\n    if (_listenerThread != NULL) {\n        delete _listenerThread;\n    }\n}\n\n}\n"
  },
  {
    "path": "src/naming/subscribe/UdpNamingServiceListener.h",
    "content": "//\n// Created by liuhanyu on 2020/9/26.\n//\n\n#ifndef NACOS_SDK_CPP_UDPLSNR_H_\n#define NACOS_SDK_CPP_UDPLSNR_H_\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n#include \"src/factory/ObjectConfigData.h\"\n#include \"src/thread/Thread.h\"\n#include \"Compatibility.h\"\n\n#define UDP_MSS 64 * 1024\n\nnamespace nacos{\n\ntypedef struct {\n    NacosString type;\n    long lastRefTime;\n    NacosString data;\n} PushPacket;\n\nclass UdpNamingServiceListener {\nprivate:\n    ObjectConfigData *_objectConfigData;\n    volatile bool _started;\n    int sockfd;\n    int udpReceiverPort;\n    struct sockaddr_in cliaddr;\n    char receiveBuffer[UDP_MSS];\n    //assume the max compress ratio = 90%\n    char uncompressedData[UDP_MSS * 10];\n    Thread *_listenerThread;\n\n    void initializeUdpListener() NACOS_THROW(NacosException);\n    static void *listenerThreadFunc(void *param);\n    bool unGzip(char *inBuffer, size_t inSize);\npublic:\n    UdpNamingServiceListener(ObjectConfigData *objectConfigData);\n    ~UdpNamingServiceListener();\n    void start();\n    void stop();\n};\n\n}//namespace nacos\n#endif //NACOS_SDK_CPP_UDPLSNR_H_\n"
  },
  {
    "path": "src/security/SecurityManager.cpp",
    "content": "//\n// Created by liuhanyu on 2020/11/28.\n//\n\n#include \"SecurityManager.h\"\n#include \"src/json/JSON.h\"\n#include \"src/utils/RandomUtils.h\"\n#include \"src/utils/TimeUtils.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"constant/ConfigConstant.h\"\n\nusing namespace std;\nnamespace nacos {\nSecurityManager::SecurityManager(ObjectConfigData *objectConfigData) {\n    _objectConfigData = objectConfigData;\n    _started = false;\n    _tokenRefreshThread = new Thread(\"TokenRefreshThread\", tokenRefreshThreadFunc, (void*)this);\n}\nvoid SecurityManager::doLogin(const NacosString &serverAddr) NACOS_THROW(NacosException, NetworkException) {\n    //TODO:refactor string constants\n    NacosString url = serverAddr + \"/\" + _objectConfigData->_appConfigManager->getContextPath() + \"/v1/auth/users/login\";\n    list <NacosString> headers;\n    list <NacosString> paramValues;\n\n    const NacosString &username = _objectConfigData->_appConfigManager->get(PropertyKeyConst::AUTH_USERNAME);\n    const NacosString &password = _objectConfigData->_appConfigManager->get(PropertyKeyConst::AUTH_PASSWORD);\n\n    paramValues.push_back(\"username\");\n    paramValues.push_back(username);\n    paramValues.push_back(\"password\");\n    paramValues.push_back(password);\n\n    HttpResult result = _objectConfigData->_httpCli->httpPost(url, headers, paramValues, NULLSTR, 3000);\n\n    _accessToken = JSON::Json2AccessToken(result.content);\n}\n\nvoid SecurityManager::login() NACOS_THROW (NacosException) {\n    WriteGuard writeGuard(_rwLock);\n    list <NacosServerInfo> serversToTry = _objectConfigData->_serverListManager->getServerList();\n    size_t nr_servers = serversToTry.size();\n    if (nr_servers == 0) {\n        throw NacosException(NacosException::NO_SERVER_AVAILABLE, \"No available server when getting access token\");\n    }\n\n    size_t start = 0;\n\n    if (nr_servers > 1) {\n        start = RandomUtils::random(0, nr_servers - 1);\n    }\n\n    for (size_t nr_tries = 0; nr_tries < nr_servers; nr_tries++) {\n        const NacosServerInfo &curServer = ParamUtils::getNthElem(serversToTry, (nr_tries + start) % nr_servers);\n        NacosString serverAddr = curServer.getCompleteAddress();\n        try {\n            //the method will throw if there's something wrong(e.g.: network problem)\n            doLogin(serverAddr);\n        } catch (NetworkException &e) {\n            //continue to try next node\n            continue;\n        } catch (NacosException &e) {\n            //for some cases, e.g.:invalid username/password,\n            //we should throw exception directly since retry on another node will not correct this problem\n            if (e.errorcode() == NacosException::INVALID_LOGIN_CREDENTIAL) {\n                /**\n                 * Here we don't need to keep log for it, because there are 3 situations where we will call this login() routine:\n                 * 1. Initialization stage of NamingService\n                 * 2. Initialization stage of ConfigService\n                 * 3. tokenRefreshThreadFunc's invocation of this routine to refresh the credentials\n                 * In case 1 and case 2, the program will crash, because these situations are considered as a config error of the program, so let it crash\n                 * In case 3, the log is printed by tokenRefreshThreadFunc to remind the dev-ops to correct the config\n                */\n                throw e;\n            }\n            log_error(\"Unknown error while login to server, e:%d = %s\\n\", e.errorcode(), e.what());\n            continue;\n        }\n        //login succeeded\n        return;\n    }\n    //this is (usually) a network problem, the caller (thread) should handle this\n    throw NacosException(NacosException::ALL_SERVERS_TRIED_AND_FAILED, \"Login failed after all servers are tried\");\n}\n\nNacosString &SecurityManager::getAccessToken() {\n    ReadGuard _readGuard(_rwLock);\n    return _accessToken.accessToken;\n}\n\nvoid SecurityManager::addAccessToken2Req(std::list<NacosString> &parameter){\n    ReadGuard _readGuard(_rwLock);\n    parameter.push_back(\"accessToken\");\n    parameter.push_back(_accessToken.accessToken);\n}\n\nSecurityManager::~SecurityManager() {\n    stop();\n    delete _tokenRefreshThread;\n    _tokenRefreshThread = NULL;\n}\n\nvoid SecurityManager::sleepWithRunStatusCheck(long _milliSecsToSleep) {\n    if (_milliSecsToSleep == 0) {\n        return;\n    }\n    long granularity = 10;\n    long sleep_start_time = TimeUtils::getCurrentTimeInMs();\n    long sleep_end_time = sleep_start_time + _milliSecsToSleep;\n    while (_started) {\n        if (TimeUtils::getCurrentTimeInMs() >= sleep_end_time) {\n            break;\n        }\n        sleep(granularity);\n    }\n}\n\nvoid *SecurityManager::tokenRefreshThreadFunc(void *param) {\n    SecurityManager *thisObj = (SecurityManager*)param;\n    log_debug(\"In thread SecurityManager::tokenRefreshThreadFunc\\n\");\n    while (thisObj->_started) {\n        try {\n            log_debug(\"Ttl got from nacos server:%ld\\n\", thisObj->_accessToken.tokenTtl);\n            thisObj->sleepWithRunStatusCheck(thisObj->_accessToken.tokenTtl * 1000);\n            log_debug(\"Trying to login...\\n\");\n            thisObj->login();\n        } catch (NacosException &e) {\n            if (e.errorcode() == NacosException::INVALID_LOGIN_CREDENTIAL) {\n                /**\n                 * invalid credential while the application is running, wait for a moment and retry\n                 * since the existing data in the nacos client is still usable for the application\n                 * we should keep the application alive for the Availability, but the Consistency, in this case, is NOT guaranteed\n                 * the error log reminds the dev-ops to check the config\n                 */\n                log_error(\"Invalid credential, please check your server settings!\\n\");\n                sleep(30);\n            } else if (e.errorcode() == NacosException::ALL_SERVERS_TRIED_AND_FAILED) {\n                log_warn(\"Network down, sleep for 30 secs and retry\\n\");\n                sleep(30);//network down, wait for a moment\n                continue;\n            } else {\n                //unknown error, there should be a better way to handle this situation\n                log_error(\"Unknown error happend, code: %d, reason: %s\\n\", e.errorcode(), e.what());\n                sleep(30);//unknown error, wait for 30 sec and continue\n                continue;\n            }\n        }\n    }\n    return NULL;\n}\n\nvoid SecurityManager::start() {\n    if (_started) {\n        return;\n    }\n\n    _started = true;\n    _tokenRefreshThread->start();\n}\n\nvoid SecurityManager::stop() {\n    if (!_started) {\n        return;\n    }\n    _started = false;\n    _tokenRefreshThread->kill();\n    _tokenRefreshThread->join();\n}\n}//nacos"
  },
  {
    "path": "src/security/SecurityManager.h",
    "content": "//\n// Created by liuhanyu on 2020/11/28.\n//\n\n#ifndef NACOS_SDK_CPP_SECURITYMANAGER_H\n#define NACOS_SDK_CPP_SECURITYMANAGER_H\n\n#include \"src/config/AppConfigManager.h\"\n#include \"src/http/IHttpCli.h\"\n#include \"src/server/ServerListManager.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos {\n\nstruct AccessToken {\n    NacosString accessToken;\n    long tokenTtl;\n    bool globalAdmin;\n    long lastRefTime;\n    AccessToken() {\n        accessToken = \"\";\n        tokenTtl = 0;\n        globalAdmin = false;\n        lastRefTime = 0;\n    }\n};\n\nclass SecurityManager {\nprivate:\n    ObjectConfigData *_objectConfigData;\n    AccessToken _accessToken;\n    void doLogin(const NacosString &serverAddr) NACOS_THROW(NacosException, NetworkException);\n    RWLock _rwLock;\n    volatile bool _started;\n    static void * tokenRefreshThreadFunc(void *param);\n    Thread *_tokenRefreshThread;\n    void sleepWithRunStatusCheck(long _milliSecsToSleep);\npublic:\n    SecurityManager(ObjectConfigData *objectConfigData);\n    ~SecurityManager();\n    void login() NACOS_THROW (NacosException);\n    NacosString &getAccessToken();\n    void addAccessToken2Req(std::list<NacosString> &parameter);\n    void start();\n    void stop();\n};\n}\n\n#endif //NACOS_SDK_CPP_SECURITYMANAGER_H\n"
  },
  {
    "path": "src/server/NacosServerInfo.h",
    "content": "//\n// Created by Liu, Hanyu on 2020/9/4.\n//\n\n#ifndef NACOS_SDK_CPP_NACOSSERVERINFO_H\n#define NACOS_SDK_CPP_NACOSSERVERINFO_H\n\n#include <ostream>\n#include \"NacosString.h\"\n\nnamespace nacos{\n//a instance of nacos naming service\n\nclass NacosServerInfo {\nprivate:\n    int mode;//1 - http/2 - https\n    NacosString ip;\n    int port;\n    NacosString site;\n    float weight;\n    float adWeight;\n    bool alive;\n    long lastRefTime;\n    NacosString lastRefTimeStr;\n    NacosString key;\npublic:\n    enum MODE {\n        mode_http = 1,\n        mode_http_safe\n    };\n\n    int getMode() const {\n        return mode;\n    }\n\n    void setMode(int mode) {\n        NacosServerInfo::mode = mode;\n    }\n\n    const NacosString getIp() const {\n        return ip;\n    }\n\n    void setIp(const NacosString &ip) {\n        NacosServerInfo::ip = ip;\n    }\n\n    int getPort() const {\n        return port;\n    }\n\n    void setPort(int port) {\n        NacosServerInfo::port = port;\n    }\n\n    const NacosString getSite() const {\n        return site;\n    }\n\n    void setSite(const NacosString &site) {\n        NacosServerInfo::site = site;\n    }\n\n    float getWeight() const {\n        return weight;\n    }\n\n    void setWeight(float weight) {\n        NacosServerInfo::weight = weight;\n    }\n\n    float getAdWeight() const {\n        return adWeight;\n    }\n\n    void setAdWeight(float adWeight) {\n        NacosServerInfo::adWeight = adWeight;\n    }\n\n    bool isAlive() const {\n        return alive;\n    }\n\n    void setAlive(bool alive) {\n        NacosServerInfo::alive = alive;\n    }\n\n    long getLastRefTime() const {\n        return lastRefTime;\n    }\n\n    void setLastRefTime(long lastRefTime) {\n        NacosServerInfo::lastRefTime = lastRefTime;\n    }\n\n    const NacosString getLastRefTimeStr() const {\n        return lastRefTimeStr;\n    }\n\n    void setLastRefTimeStr(const NacosString &lastRefTimeStr) {\n        NacosServerInfo::lastRefTimeStr = lastRefTimeStr;\n    }\n\n    const NacosString getKey() const {\n        return key;\n    }\n\n    void setKey(const NacosString &key) {\n        NacosServerInfo::key = key;\n    }\n\n    NacosString getCompleteAddress() const {\n        if (port != 0) {\n            return ip + \":\" + NacosStringOps::valueOf(port);\n        } else {\n            return ip;\n        }\n    }\n\n    NacosString toString() const {\n        NacosString res;\n        res = ip + \":\" + NacosStringOps::valueOf(port);\n        return res;\n    }\n\n    bool operator<(const NacosServerInfo &other) const {\n        return getCompleteAddress().compare(other.getCompleteAddress());\n    }\n\n    bool operator==(const NacosServerInfo &other) const {\n        return getCompleteAddress().compare(other.getCompleteAddress()) == 0;\n    }\n};\n}//namespace nacos\n\n#endif //NACOS_SDK_CPP_NACOSSERVERINFO_H\n"
  },
  {
    "path": "src/server/ServerListManager.cpp",
    "content": "#include <stdlib.h>\n#include <unistd.h>\n#include \"ServerListManager.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"src/log/Logger.h\"\n#include \"src/json/JSON.h\"\n\nusing namespace std;\n\nnamespace nacos{\nvoid ServerListManager::addToSrvList(NacosString &address) {\n    address = ParamUtils::trim(address);\n    NacosString address_lc = ParamUtils::toLower(address);\n    if (address_lc.find(\"http://\") == 0 ||\n            address_lc.find(\"https://\") == 0) {\n        size_t startPos = address.find(':');//4=http,5=https\n        //use http://someaddress[:port] as server address\n        NacosString ip = address;\n        int port = PropertyKeyConst::NACOS_DEFAULT_PORT;\n        size_t pos = address.find_last_of(':');\n        if (pos != 4 && pos != 5) {\n            NacosString portStr = address.substr(pos + 1);\n            port = atoi(portStr.c_str());\n            ip = address.substr(0, pos);\n        }\n        NacosServerInfo curServer;\n        curServer.setKey(address);\n        curServer.setAlive(true);\n        curServer.setIp(ip);\n        curServer.setPort(port);\n        curServer.setWeight(1.0);\n        curServer.setAdWeight(1.0);\n        curServer.setMode(startPos == 4 ? NacosServerInfo::mode_http : NacosServerInfo::mode_http_safe);\n        serverList.push_back(curServer);\n    } else if (address.find(':') == std::string::npos) {\n        //If the address doesn't contain port, add 8848 as the default port for it\n        NacosServerInfo curServer;\n        curServer.setKey(\"http://\" + address + \":\" + NacosStringOps::valueOf(PropertyKeyConst::NACOS_DEFAULT_PORT));\n        curServer.setAlive(true);\n        curServer.setIp(\"http://\" + address);\n        curServer.setPort(PropertyKeyConst::NACOS_DEFAULT_PORT);\n        curServer.setWeight(1.0);\n        curServer.setAdWeight(1.0);\n        curServer.setMode(NacosServerInfo::mode_http);\n        serverList.push_back(curServer);\n    } else {\n        //user specified address & port\n        vector <NacosString> explodedAddress;\n        ParamUtils::Explode(explodedAddress, address, ':');\n        NacosServerInfo curServer;\n        curServer.setKey(\"http://\" + address);\n        curServer.setAlive(true);\n        curServer.setIp(\"http://\" + explodedAddress[0]);\n        curServer.setPort(atoi(explodedAddress[1].c_str()));\n        curServer.setWeight(1.0);\n        curServer.setAdWeight(1.0);\n        curServer.setMode(NacosServerInfo::mode_http);\n        serverList.push_back(curServer);\n    }\n}\n\nServerListManager::ServerListManager(list <NacosString> &fixed) {\n    started = false;\n    isFixed = true;\n    _pullThread = NULL;\n    refreshInterval = 30000;\n    for (list<NacosString>::iterator it = fixed.begin(); it != fixed.end(); it++) {\n        addToSrvList(*it);\n    }\n}\n\nNacosString ServerListManager::getCurrentServerAddr() {\n    //By default, this function returns a server in the serverList randomly\n    //later we should sort it according to the java client and use cache\n    ReadGuard _readGuard(rwLock);\n    size_t max_serv_slot = serverList.size();\n    srand(time(NULL));\n    int to_skip = rand() % max_serv_slot;\n    std::list<NacosServerInfo>::iterator it = serverList.begin();\n    for (int skipper = 0; skipper < to_skip; skipper++) {\n        it++;\n    }\n\n    return it->getCompleteAddress();\n}\n\nvoid ServerListManager::initAll() NACOS_THROW(NacosException) {\n    serverList.clear();\n    Properties props = _objectConfigData->_appConfigManager->getAllConfig();\n    if (props.contains(PropertyKeyConst::SERVER_ADDR)) {//Server address is configured\n        isFixed = true;\n        NacosString server_addr = props[PropertyKeyConst::SERVER_ADDR];\n\n        vector <NacosString> explodedServers;\n        ParamUtils::Explode(explodedServers, server_addr, ',');\n        for (vector<NacosString>::iterator it = explodedServers.begin(); it != explodedServers.end(); it++) {\n            addToSrvList(*it);\n        }\n        serverList.sort();\n    } else {//use endpoint mode to pull nacos server info from server\n        if (!props.contains(PropertyKeyConst::ENDPOINT)) {\n            throw NacosException(NacosException::CLIENT_INVALID_PARAM, \"no server address specified and the endpoint is blank\");\n        }\n\n        isFixed = false;\n        const NacosString& endpoint = getEndpoint();\n        NacosString endpoint_lc = ParamUtils::toLower(endpoint);\n        //endpoint doesn't start with http or https prefix, consider it as http\n        if (endpoint_lc.find(\"http://\") == NacosString::npos && endpoint_lc.find(\"https://\") == NacosString::npos) {\n            endpoint_lc = \"http://\" + endpoint_lc;\n        }\n        addressServerUrl = endpoint_lc + \":\" + NacosStringOps::valueOf(getEndpointPort());\n        const NacosString& endpointContextPath = getEndpointContextPath();\n        const NacosString& contextPath = endpointContextPath.empty() ? getContextPath() : endpointContextPath;\n        if (!contextPath.empty()) {\n            if (contextPath[0] != '/') {\n                // not start by ’/‘\n                addressServerUrl += (\"/\" + contextPath);\n            } else {\n                addressServerUrl += contextPath;\n            }\n        }\n\n        const NacosString& clusterName = getClusterName();\n        if (!clusterName.empty()) {\n            if (clusterName[0] != '/') {\n                addressServerUrl += (\"/\" + clusterName);\n            } else {\n                addressServerUrl += clusterName;\n            }\n        }\n\n        const NacosString& namespaceInfo = getNamespace();\n        if (!namespaceInfo.empty()) {\n            addressServerUrl += (\"?namespace=\" + namespaceInfo);\n        }\n\n        const NacosString& endpointQueryParams = getEndpointQueryParams();\n        if (!endpointQueryParams.empty()) {\n            addressServerUrl += ((namespaceInfo.empty() ? \"?\" : \"&\") + endpointQueryParams);\n        }\n\n        log_debug(\"Assembled addressServerUrl:%s\\n\", addressServerUrl.c_str());\n        serverList = pullServerList();\n        start();\n    }\n}\n\nServerListManager::ServerListManager(ObjectConfigData *objectConfigData) NACOS_THROW(NacosException) {\n    started = false;\n    _pullThread = NULL;\n    _objectConfigData = objectConfigData;\n    refreshInterval = atoi(_objectConfigData->_appConfigManager->get(PropertyKeyConst::SRVLISTMGR_REFRESH_INTERVAL).c_str());\n    initAll();\n}\n\nlist <NacosServerInfo> ServerListManager::tryPullServerListFromNacosServer() NACOS_THROW(NacosException) {\n    std::list <NacosString> headers;\n    std::list <NacosString> paramValues;\n    size_t maxSvrSlot = serverList.size();\n    if (maxSvrSlot == 0) {\n        throw NacosException(0, \"failed to get nacos servers, raison: no server(s) available\");\n    }\n    log_debug(\"nr_servers:%d\\n\", maxSvrSlot);\n    srand(time(NULL));\n\n    long _read_timeout = _objectConfigData->_appConfigManager->getServeReqTimeout();\n    NacosString errmsg;\n    for (size_t i = 0; i < serverList.size(); i++) {\n        size_t selectedServer = rand() % maxSvrSlot;\n        const NacosServerInfo &server = ParamUtils::getNthElem(serverList, selectedServer);\n        log_debug(\"selected_server:%d\\n\", selectedServer);\n        log_debug(\"Trying to access server:%s\\n\", server.getCompleteAddress().c_str());\n        try {\n            HttpResult serverRes = _objectConfigData->_httpDelegate->httpGet(\n                    server.getCompleteAddress() + \"/\" + _objectConfigData->_appConfigManager->getContextPath() + \"/\"\n                    + ConfigConstant::PROTOCOL_VERSION + \"/\" + ConfigConstant::GET_SERVERS_PATH,\n                    headers, paramValues, NULLSTR, _read_timeout);\n            return JSON::Json2NacosServerInfo(serverRes.content);\n        }\n        catch (NacosException &e) {\n            errmsg = e.what();\n            log_error(\"request %s failed.\\n\", server.getCompleteAddress().c_str());\n        }\n        catch (exception &e) {\n            errmsg = e.what();\n            log_error(\"request %s failed.\\n\", server.getCompleteAddress().c_str());\n        }\n\n        selectedServer = (selectedServer + 1) % serverList.size();\n    }\n\n    throw NacosException(0,\n                         \"failed to get nacos servers after all servers(\" + toString() + \") tried: \"\n                         + errmsg);\n}\n\nlist <NacosServerInfo> ServerListManager::pullServerList() NACOS_THROW(NacosException) {\n    std::list <NacosString> headers;\n    std::list <NacosString> paramValues;\n\n    long _read_timeout = _objectConfigData->_appConfigManager->getServeReqTimeout();\n    if (!NacosStringOps::isNullStr(addressServerUrl)) {\n        HttpResult serverRes = _objectConfigData->_httpDelegate->httpGet(addressServerUrl, headers, paramValues, NULLSTR,\n                                                _read_timeout);\n        list<NacosString> explodedServerList;\n        ParamUtils::Explode(explodedServerList, serverRes.content, '\\n');\n        list <NacosServerInfo> serversPulled;\n\n        for (list<NacosString>::const_iterator it = explodedServerList.begin();\n                it != explodedServerList.end(); it++) {\n            NacosServerInfo curServer;\n            size_t pos = it->find(\":\");\n            if (pos == std::string::npos) {\n                curServer.setIp(*it);\n                curServer.setPort(8848);\n            } else {\n                NacosString ip = it->substr(0, pos);\n                NacosString port = it->substr(pos + 1);\n\n                curServer.setIp(ip);\n                curServer.setPort(atoi(port.c_str()));\n            }\n            curServer.setAlive(true);\n            serversPulled.push_back(curServer);\n        }\n\n        serversPulled.sort();\n\n        log_debug(\"pullServerList: servers list: %s\\n\", serverListToString(serversPulled).c_str());\n        return serversPulled;\n    }\n    //usually this should not be happening\n    throw NacosException(0, \"addressServerUrl is not set, please config it on properties\");\n}\n\nstd::list <NacosServerInfo> ServerListManager::__debug() {\n    return tryPullServerListFromNacosServer();\n}\n\nNacosString ServerListManager::serverListToString(const std::list <NacosServerInfo> &serverList) {\n    NacosString res;\n    bool first = true;\n    for (list<NacosServerInfo>::const_iterator it = serverList.begin(); it != serverList.end(); it++) {\n        if (first) {\n            first = false;\n        } else {\n            res += \",\";\n        }\n        res += it->toString();\n    }\n\n    return res;\n}\n\nNacosString ServerListManager::toString() const {\n    return serverListToString(serverList);\n}\n\nvoid *ServerListManager::pullWorkerThread(void *param) {\n    ServerListManager *thisMgr = (ServerListManager *) param;\n    while (thisMgr->started) {\n        try {\n            bool changed = false;\n            list <NacosServerInfo> serverList = thisMgr->pullServerList();\n\n            {\n                ReadGuard _readGuard(thisMgr->rwLock);\n                if (serverList != thisMgr->serverList) {\n                    log_debug(\"Servers got from nacos differs from local one, updating...\\n\");\n                    changed = true;\n                }\n            }\n\n            if (changed) {\n                WriteGuard _writeGuard(thisMgr->rwLock);\n                log_debug(\"updated!\\n\");\n                thisMgr->serverList = serverList;\n            }\n        }\n        catch (NacosException &e) {\n            //Error occured during the invocation, sleep for a longer time\n            sleep(thisMgr->refreshInterval / 1000);\n        }\n        sleep(thisMgr->refreshInterval / 1000);\n    }\n\n    return NULL;\n}\n\nvoid ServerListManager::start() {\n    if (started && !isFixed) {\n        return;\n    }\n\n    started = true;\n\n    if (_pullThread == NULL) {\n        NacosString threadName = getClusterName() + \",\" + getEndpoint() + \":\" +\n                                 NacosStringOps::valueOf(getEndpointPort()) + \"-\" + getNamespace();\n        _pullThread = new Thread(threadName, pullWorkerThread, (void *) this);\n    }\n    _pullThread->start();\n}\n\nvoid ServerListManager::stop() {\n    if (!started) {\n        return;\n    }\n\n    started = false;\n    if (_pullThread != NULL) {\n        _pullThread->join();\n        _pullThread = NULL;\n    }\n}\n\nconst NacosString &ServerListManager::getContextPath() const {\n    return _objectConfigData->_appConfigManager->getContextPath();\n}\n\nServerListManager::~ServerListManager() {\n    stop();\n    if (_pullThread != NULL) {\n        delete _pullThread;\n        _pullThread = NULL;\n    }\n}\n\nint ServerListManager::getServerCount() {\n    int count = 0;\n    {\n        ReadGuard _readGuard(rwLock);\n        count = serverList.size();\n    }\n    return count;\n};\n\nlist <NacosServerInfo> ServerListManager::getServerList() {\n    //further optimization could be implemented here if the server list cannot be changed during runtime\n    std::list <NacosServerInfo> res;\n    {\n        ReadGuard _readGuard(rwLock);\n        res = serverList;\n    }\n    return res;\n};\n}//namespace nacos\n"
  },
  {
    "path": "src/server/ServerListManager.h",
    "content": "#ifndef __SERVER_LIST_MGR_H_\n#define __SERVER_LIST_MGR_H_\n\n#include <list>\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"NacosExceptions.h\"\n#include \"src/server/NacosServerInfo.h\"\n#include \"src/http/HttpDelegate.h\"\n#include \"src/thread/Thread.h\"\n#include \"src/config/AppConfigManager.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/thread/RWLock.h\"\n#include \"src/factory/ObjectConfigData.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass ServerListManager {\nprivate:\n    //status info\n    bool started;\n    bool isFixed;\n\n    //Nacos server info\n    std::list <NacosServerInfo> serverList;\n\n    //url to pull nacos cluster nodes info from\n    NacosString addressServerUrl;\n\n    //Worker thread\n    Thread *_pullThread;\n\n    static void *pullWorkerThread(void *param);\n\n    long refreshInterval;//in Millis\n    RWLock rwLock;//to lock the serverList\n\n    void initAll() NACOS_THROW(NacosException);\n\n    void addToSrvList(NacosString &address);\n\n    std::list <NacosServerInfo> tryPullServerListFromNacosServer() NACOS_THROW(NacosException);\n\n    std::list <NacosServerInfo> pullServerList() NACOS_THROW(NacosException);\n\n    ObjectConfigData *_objectConfigData;\n\n    static NacosString serverListToString(const std::list <NacosServerInfo> &serverList);\n\npublic:\n    //Cluster info\n    inline const NacosString& getClusterName() { return _objectConfigData->_appConfigManager->get(PropertyKeyConst::CLUSTER_NAME); };\n\n    inline const NacosString& getEndpoint() { return _objectConfigData->_appConfigManager->get(PropertyKeyConst::ENDPOINT); };\n\n    inline int getEndpointPort() { return atoi(_objectConfigData->_appConfigManager->get(PropertyKeyConst::ENDPOINT_PORT).c_str()); };\n\n    inline const NacosString &getContextPath() const;\n\n    inline const NacosString& getEndpointContextPath() { return  _objectConfigData->_appConfigManager->get(PropertyKeyConst::ENDPOINT_CONTEXT_PATH); }\n\n    inline const NacosString& getNamespace() { return _objectConfigData->_appConfigManager->get(PropertyKeyConst::NAMESPACE); };\n\n    inline const NacosString& getEndpointQueryParams() { return _objectConfigData->_appConfigManager->get(PropertyKeyConst::ENDPOINT_QUERY_PARAMS); }\n\n    std::list <NacosServerInfo> __debug();//DO NOT use, may be changed without prior notification\n\n    HttpDelegate *getHttpDelegate() const { return _objectConfigData->_httpDelegate; };\n\n    void setHttpDelegate(HttpDelegate *httpDelegate) { _objectConfigData->_httpDelegate = httpDelegate; };\n\n    AppConfigManager *getAppConfigManager() const { return _objectConfigData->_appConfigManager; };\n\n    void setAppConfigManager(AppConfigManager *_appConfigManager) { _objectConfigData->_appConfigManager = _appConfigManager; };\n\n    ServerListManager(std::list <NacosString> &fixed);\n\n    ServerListManager(ObjectConfigData *objectConfigData) NACOS_THROW(NacosException);\n\n    NacosString getCurrentServerAddr();\n\n    int getServerCount();\n\n    std::list <NacosServerInfo> getServerList();\n\n    NacosString toString() const;\n\n    void start();\n\n    void stop();\n\n    ~ServerListManager();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/thread/BlockingQueue.h",
    "content": "#ifndef __BLOCKING_Q_H_\n#define __BLOCKING_Q_H_\n\n#include <deque>\n#include \"src/thread/Mutex.h\"\n/*\n* BlockingQueue.h\n* Thanks to Shuo, Chen's muduo: https://github.com/chenshuo/muduo/blob/master/muduo/base/BlockingQueue.h\n*/\n\nnamespace nacos{\ntemplate<typename T>\nclass BlockingQueue\n{\nprivate:\n\tMutex _mutex;\n\tCondition _notEmpty;\n\tCondition _notFull;\n\tstd::deque<T> _queue;\n\tsize_t _maxSize;\n\tvolatile bool _full;\n\tvolatile bool _empty;\npublic:\n\n    bool full() {\n        LockGuard lockguard(_mutex);\n        return _full;\n    };\n    bool empty() {\n        LockGuard lockguard(_mutex);\n        return _empty;\n    };\n\n\tBlockingQueue() : _mutex(), _notEmpty(_mutex), _notFull(_mutex), _maxSize(64), _full(false), _empty(true) {};\n\tBlockingQueue(size_t queueSize) : _mutex(), _notEmpty(_mutex), _notFull(_mutex), _maxSize(queueSize), _full(false), _empty(true) {};\n\tvoid enqueue(const T &data)\n\t{\n\t\tLockGuard lockguard(_mutex);\n        _empty = false;\n\t\twhile (_queue.size() == _maxSize)\n\t\t{\n\t\t    _full = true;\n\t\t\t_notFull.wait();\n\t\t}\n\t\t_queue.push_back(data);\n\t\t_notEmpty.notify();\n\t}\n\n\tT dequeue()\n\t{\n\t\tLockGuard lockguard(_mutex);\n        _full = false;\n\t\twhile (_queue.empty())\n\t\t{\n\t\t    _empty = true;\n\t\t\t_notEmpty.wait();\n\t\t}\n\t\tT front = _queue.front();\n\t\t_queue.pop_front();\n\t\t_notFull.notify();\n\t\treturn front;\n\t}\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/thread/DelayedThreadPool.cpp",
    "content": "#include <algorithm>\n#include \"src/thread/DelayedThreadPool.h\"\n#include \"NacosExceptions.h\"\n\nnamespace nacos {\n\n/**\n* A thread pool that can run tasks with specified delay\n*/\nclass DelayedWorker : public Task {\nprivate:\n    DelayedThreadPool &_container;\npublic:\n    volatile bool _start;\n    DelayedWorker(DelayedThreadPool &container) : _container(container) {\n        _start = false;\n    };\n\n    void run() {\n        log_debug(\"DelayedWorker::run()\\n\");\n        while (!_container._stop_delayed_tp) {\n            _container._lockForScheduleTasks.lock();\n\n            //no data, wait until data is available\n            log_debug(\"[DelayedWorker] start to wait for task stop=%d\\n\", _container._stop);\n            if (_container._scheduledTasks.empty()) {\n                log_debug(\"[DelayedWorker] empty, wait for task\\n\");\n                if (_container._stop_delayed_tp) {\n                    _container._lockForScheduleTasks.unlock();\n                    return;\n                }\n                _container._delayTaskNotEmpty.wait();\n                log_debug(\"[DelayedWorker] wake up due to incoming event\\n\");\n            }\n\n            /*\n            * Here actually we have 2 different design patterns:\n            * 1. wait both on the _delayTaskNotEmpty condition and the nearest task to be executed\n            * 2. wait on the nearest task to be executed\n            * \n            * The advantages/disadvantages for pattern 1 (the pattern applied here).\n            * The advantages are that:\n            * 1. This design pattern is more responsive\n            * 2. For tasks that take a short time, this pattern is more effective since one worker can handle more tasks\n            * (compared with the pattern that wait() for exact one task in else {} block)\n            * \n            * The disadvantages are that:\n            * 1. Will incur more wake-ups and context-switches(I guess)\n            * 2. Not as precise as the pattern 2\n            * */\n\n            log_debug(\"[DelayedWorker] iterating on _scheduledTasks\\n\");\n            std::vector< std::pair<long, Task*> >::iterator it;\n            while ((it = _container._scheduledTasks.begin()) != _container._scheduledTasks.end()) {\n                int64_t now_time = TimeUtils::getCurrentTimeInMs();\n                log_debug(\"[DelayedWorker] now = %ld wakeup time = %ld\\n\", now_time, it->first);\n                if (it->first <= now_time) {\n                    Task *task = it->second;\n                    _container._scheduledTasks.erase(it);\n                    _container._lockForScheduleTasks.unlock();\n                    //the task can also attempt to retrieve the lock\n                    if (_container._stop_delayed_tp) {\n                        return;\n                    }\n                    task->run();\n                    _container._lockForScheduleTasks.lock();\n                    log_debug(\"[DelayedWorker] continue 2 next task\\n\");\n                } else {\n                    //awake from sleep when a stop signal is sent\n                    if (_container._stop_delayed_tp) {\n                        _container._lockForScheduleTasks.unlock();\n                        return;\n                    }\n                    _container._delayTaskNotEmpty.wait(it->first - now_time);\n                }\n            }\n\n            _container._lockForScheduleTasks.unlock();\n        }\n        _start = false;\n    }\n};\n\nDelayedThreadPool::DelayedThreadPool(const NacosString &poolName, size_t poolSize)\n:ThreadPool(poolName, poolSize),_delayTaskNotEmpty(_lockForScheduleTasks), _stop_delayed_tp(true) {\n    log_debug(\"DelayedThreadPool::DelayedThreadPool() name = %s size = %d\\n\", poolName.c_str(), poolSize);\n    if (poolSize <= 0) {\n        throw NacosException(NacosException::INVALID_PARAM, \"Poll size cannot be lesser than 0\");\n    }\n    delayTasks = new DelayedWorker*[poolSize];\n    log_debug(\"DelayedThreadPool::DelayedThreadPool initializing tasks\\n\");\n    for (size_t i = 0; i < poolSize; i++) {\n        delayTasks[i] = new DelayedWorker(*this);\n    }\n}\n\n\nDelayedThreadPool::~DelayedThreadPool() {\n    log_debug(\"DelayedThreadPool::~DelayedThreadPool\\n\");\n    if (delayTasks != NULL) {\n        for (size_t i = 0; i < _poolSize; i++) {\n            delete delayTasks[i];\n            delayTasks[i] = NULL;\n        }\n        delete [] delayTasks;\n        delayTasks = NULL;\n    }\n}\n\nstruct tagAscOrdFunctor{\n    bool operator ()(const std::pair<long, Task*> &lhs, const std::pair<long, Task*> &rhs) {\n        return lhs.first < rhs.first;\n    };\n} ascOrdFunctor = {};\n\n#include <stdio.h>\n//futureTimeToRun: time in MS\nvoid DelayedThreadPool::schedule(Task *t, long futureTimeToRun) {\n    if (_stop) {\n        return;\n    }\n    if (futureTimeToRun < 0) {\n        throw NacosException(NacosException::INVALID_PARAM, \"futureTimeToRun must not be negative\");\n    }\n    log_debug(\"DelayedThreadPool::schedule() name=%s future = %ld\\n\", t->getTaskName().c_str(), futureTimeToRun);\n    std::pair<long, Task*> scheduledTask = std::make_pair (futureTimeToRun, t);\n    {\n        LockGuard __lockSchedTasks(_lockForScheduleTasks);\n        _scheduledTasks.push_back(scheduledTask);\n        std::sort(_scheduledTasks.begin(), _scheduledTasks.end(), ascOrdFunctor);\n        _delayTaskNotEmpty.notifyAll();\n    }\n}\n\nvoid DelayedThreadPool::start() {\n    _stop_delayed_tp = false;\n    ThreadPool::start();\n    log_debug(\"DelayedThreadPool::start()\\n\");\n    for (size_t i = 0; i < _poolSize; i++) {\n        delayTasks[i]->_start = true;\n        put((Task*)delayTasks[i]);\n    }\n}\n\nvoid DelayedThreadPool::stop() {\n    if (_stop_delayed_tp) {\n        return;\n    }\n\n    _stop_delayed_tp = true;\n    _delayTaskNotEmpty.notifyAll();\n    for (std::list<Thread *>::iterator it = _threads.begin(); it != _threads.end(); it++) {\n        (*it)->kill();\n    }\n\n    ThreadPool::stop();\n}\n\n}"
  },
  {
    "path": "src/thread/DelayedThreadPool.h",
    "content": "#ifndef __DELAYED_THREAD_POOL_H_\n#define __DELAYED_THREAD_POOL_H_\n\n#include <vector>\n#include <utility>\n#include \"src/thread/ThreadPool.h\"\n#include \"src/thread/Task.h\"\n#include \"src/thread/Mutex.h\"\n\nnamespace nacos {\n\nclass DelayedWorker;\n\nclass DelayedThreadPool : public ThreadPool {\nprivate:\n    Condition _delayTaskNotEmpty;\n    Mutex _lockForScheduleTasks;//for _scheduledTasks\n    std::vector< std::pair<long, Task*> > _scheduledTasks;\n    DelayedThreadPool();\n    DelayedWorker **delayTasks;\n    volatile bool _stop_delayed_tp;\npublic:\n    DelayedThreadPool(const NacosString &poolName, size_t poolSize) ;\n    ~DelayedThreadPool();\n\n    /**\n    * schedule the execution for a task\n    * @param t the task to run\n    * @param futureTimeToRun the time (in ms) for the task to run\n    */\n    void schedule(Task *t, long futureTimeToRun);\n\n    friend class DelayedWorker;\n\n    virtual void start();\n\n    virtual void stop();\n};\n\n}\n\n#endif"
  },
  {
    "path": "src/thread/Mutex.h",
    "content": "#ifndef __MUTEX_H_\n#define __MUTEX_H_\n\n#include<iostream>\n#include <pthread.h>\n#include \"Tid.h\"\n#include \"src/utils/TimeUtils.h\"\n\n/*\n* Mutex.h\n* Author: Liu, Hanyu\n* Thanks to Shuo, Chen's muduo:\n* https://github.com/chenshuo/muduo/blob/master/muduo/base/Mutex.h\n*/\n\nnamespace nacos{\nclass Mutex {\n    friend class Condition;\n\nprivate:\n    TID_T _holder;\n    pthread_mutex_t _mutex;\npublic:\n    Mutex() { pthread_mutex_init(&_mutex, NULL); };\n\n    ~Mutex() { pthread_mutex_destroy(&_mutex); };\n\n    void lock() {\n        pthread_mutex_lock(&_mutex);\n        assignHolder();\n    };\n\n    void unlock() {\n        unassignHolder();\n        pthread_mutex_unlock(&_mutex);\n    };\n\n    pthread_mutex_t *getPthreadMutex() { return &_mutex; };\n\n    void assignHolder() { _holder = gettidv1(); };\n\n    void unassignHolder() { _holder = 0; };\n};\n\nclass Condition {\nprivate:\n    Mutex &_mutex;\n    pthread_cond_t _cond;\npublic:\n    Condition(Mutex &mutex) : _mutex(mutex) { pthread_cond_init(&_cond, NULL); };\n\n    ~Condition() { pthread_cond_destroy(&_cond); };\n\n    int wait() {\n        return pthread_cond_wait(&_cond, _mutex.getPthreadMutex());\n    }\n\n    int wait(long millis) {\n        struct timeval now;\n        struct timespec wakeup_time;\n\n        TimeUtils::getCurrentTimeInStruct(now);\n        now.tv_usec = now.tv_usec + millis * 1000;\n        now.tv_sec = now.tv_sec + now.tv_usec / 1000000;\n        now.tv_usec = now.tv_usec % 1000000;\n\n        wakeup_time.tv_nsec = now.tv_usec * 1000;\n        wakeup_time.tv_sec = now.tv_sec;\n        //std::cout << \" millis:\" << millis\n        //<< \"   wakeup time:sec:\" << wakeup_time.tv_sec << \"  nsec:\" << wakeup_time.tv_nsec << std::endl;\n\n        return pthread_cond_timedwait(&_cond, _mutex.getPthreadMutex(), &wakeup_time);\n    }\n\n    void notify() {\n        pthread_cond_signal(&_cond);\n    }\n\n    void notifyAll() {\n        pthread_cond_broadcast(&_cond);\n    }\n};\n\nclass LockGuard {\nprivate:\n    Mutex &_mutex;\npublic:\n    LockGuard(Mutex &mutex) : _mutex(mutex) { _mutex.lock(); };\n\n    ~LockGuard() { _mutex.unlock(); };\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/thread/RWLock.h",
    "content": "#ifndef __RWLOCK_H_\n#define __RWLOCK_H_\n\n#include <pthread.h>\n#include <unistd.h>\n\n/*\n* Mutex.h\n* Author: Liu, Hanyu\n* An encapsulation of pthread_rwlock\n*/\n\nnamespace nacos{\nclass RWLock {\nprivate:\n    pthread_rwlock_t _pthread_rwlock;\npublic:\n    RWLock() { pthread_rwlock_init(&_pthread_rwlock, NULL); };\n\n    ~RWLock() { pthread_rwlock_destroy(&_pthread_rwlock); };\n\n    int unlock() { return pthread_rwlock_unlock(&_pthread_rwlock); };\n\n    int readLock() { return pthread_rwlock_rdlock(&_pthread_rwlock); };\n\n    int writeLock() { return pthread_rwlock_wrlock(&_pthread_rwlock); };\n};\n\nclass ReadGuard {\nprivate:\n    RWLock &_rwLock;\npublic:\n    ReadGuard(RWLock &rwLock) : _rwLock(rwLock) {\n        _rwLock.readLock();\n    }\n\n    ~ReadGuard() { _rwLock.unlock(); }\n};\n\nclass WriteGuard {\nprivate:\n    RWLock &_rwLock;\npublic:\n    WriteGuard(RWLock &rwLock) : _rwLock(rwLock) {\n        _rwLock.writeLock();\n    }\n\n    ~WriteGuard() { _rwLock.unlock(); }\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/thread/Task.h",
    "content": "#ifndef __TASK_H_\n#define __TASK_H_\n\n#include \"NacosString.h\"\n\nnamespace nacos{\nclass Task {\nprivate:\n    NacosString _taskName;\npublic:\n    virtual void run() = 0;\n\n    virtual ~Task() {};\n\n    void setTaskName(const NacosString &taskName) { _taskName = taskName; };\n\n    const NacosString &getTaskName() const { return _taskName; };\n};\n\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/thread/Thread.cpp",
    "content": "#include \"Thread.h\"\n\nusing namespace nacos;\n\nstruct sigaction Thread::old_action;\n\nvoid Thread::Init() {\n    struct sigaction action;\n\n    action.sa_flags = 0;\n    action.sa_handler = empty_signal_handler;\n    sigemptyset(&action.sa_mask);\n\n    sigaction(THREAD_STOP_SIGNAL, &action, &Thread::old_action);\n};\n\nvoid Thread::DeInit() {\n    sigaction(THREAD_STOP_SIGNAL, &Thread::old_action, NULL);\n};\n\nvoid *Thread::threadFunc(void *param) {\n    Thread *currentThread = (Thread *) param;\n    currentThread->_tid = gettidv1();\n\n    try {\n        return currentThread->_function(currentThread->_threadData);\n    }\n    catch (std::exception &e) {\n        currentThread->_function = NULL;\n        log_error(\"Exception happens when executing:\\n\");\n        log_error(\"Thread Name:%s Thread Id:%d\\n\", currentThread->_threadName.c_str(), currentThread->_tid);\n        log_error(\"Raison:%s\", e.what());\n        abort();\n    }\n    catch (...) {\n        currentThread->_function = NULL;\n        log_error(\"Unknown exception happens when executing:\\n\");\n        log_error(\"Thread Name:%s Thread Id:%d\\n\", currentThread->_threadName.c_str(), currentThread->_tid);\n        throw;\n    }\n}\n\nvoid Thread::start() {\n    _start = true;\n    pthread_create(&_thread, NULL, threadFunc, (void *) this);\n}\n\nvoid Thread::join() {\n    log_debug(\"Calling Thread::join() on %s\\n\", _threadName.c_str());\n    if (!_start) {\n        log_debug(\"Thread::join() called on stopped thread for %s\\n\", _threadName.c_str());\n        return;\n    }\n\n    pthread_join(_thread, NULL);\n}\n\nvoid Thread::kill() {\n    pthread_kill(_thread, THREAD_STOP_SIGNAL);\n}"
  },
  {
    "path": "src/thread/Thread.h",
    "content": "#ifndef __THREAD_H_\n#define __THREAD_H_\n\n#include <exception>\n#include <stdlib.h>\n#include <signal.h>\n#include <sys/types.h>\n#include \"NacosString.h\"\n#include \"src/log/Logger.h\"\n#include \"src/thread/Tid.h\"\n\n#define THREAD_STOP_SIGNAL SIGUSR1\n\nnamespace nacos{\ntypedef void *(*ThreadFn)(void *);\n\n/*\n* Thread.h\n* Author: Liu, Hanyu\n* This is NOT like the thread class in Java!\n* It's just a simple encapsulation of pthread_create() and pthread_join\n* It doesn't have a virtual run() function,\n * a function pointer(ThreadFn) should be passed to the constructor so it will be used as the function pointer parameter for pthread_create\n*/\nclass Thread {\nprivate:\n    NacosString _threadName;\n    pthread_t _thread;\n    ThreadFn _function;\n    //TODO:thread id\n    TID_T _tid;\n    bool _start;\n    void *_threadData;\n\n    Thread() {};\n\n    static void empty_signal_handler(int signum) {};\n    static struct sigaction old_action;\npublic:\n    static void Init();\n    static void DeInit();\n\n    void setThreadName(const NacosString &threadName) { _threadName = threadName; };\n\n    NacosString getThreadName() { return _threadName; };\n\n    static void *threadFunc(void *param);\n\n    Thread(const NacosString &threadName, ThreadFn fn)\n            : _threadName(threadName), _function(fn), _threadData(NULL) {\n        _start = false;\n    };\n\n    Thread(const NacosString &threadName, ThreadFn fn, void *threadData)\n            : _threadName(threadName), _function(fn), _threadData(threadData) {\n        _start = false;\n    };\n\n    ~Thread() {\n        _start = false;\n    }\n\n    void start();\n\n    void join();\n\n    void kill();\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/thread/ThreadLocal.h",
    "content": "#ifndef __THREAD_LOCAL_H_\n#define __THREAD_LOCAL_H_\n\n#include <pthread.h>\n\nnamespace nacos{\ntemplate <typename T>\nclass ThreadLocal;\ntemplate <typename T>\nstruct ObjectWrapper {\n    T wrappedObject;\n    ThreadLocal<T> *threadLocalObj;\n};\n\ntemplate <typename T>\nclass ThreadLocal{\nprivate:\n    pthread_key_t pthreadKey;\n    T _defaultValue;\n    static void destroyer(void *param) {\n        ObjectWrapper<T> *wrapper = reinterpret_cast< ObjectWrapper<T> *>(param);\n        wrapper->threadLocalObj->onDestroy(&wrapper->wrappedObject);\n        delete wrapper;\n    }\n\n    ObjectWrapper<T> *getWrapper() const {\n        ObjectWrapper<T> *wrapper = reinterpret_cast< ObjectWrapper<T> *>(pthread_getspecific(pthreadKey));\n        return wrapper;\n    }\n\n    ObjectWrapper<T> *createWrapper() {\n        ObjectWrapper<T> *wrapper = new ObjectWrapper<T>;\n        wrapper->threadLocalObj = this;\n        onCreate(&wrapper->wrappedObject);\n        pthread_setspecific(pthreadKey, reinterpret_cast<void *>(wrapper));\n\n        return wrapper;\n    }\npublic:\n    ThreadLocal() {\n        /* init the curl session */\n        pthread_key_create(&pthreadKey, destroyer);\n    }\n\n    ThreadLocal(T defaultValue) {\n        _defaultValue = defaultValue;\n        /* init the curl session */\n        pthread_key_create(&pthreadKey, destroyer);\n    }\n\n    void set(T value) {\n        ObjectWrapper<T> *wrapper = getWrapper();\n        if (wrapper == NULL) {\n            wrapper = createWrapper();\n        }\n        wrapper->wrappedObject = value;\n    }\n\n    T get() {\n        ObjectWrapper<T> *wrapper = getWrapper();\n        if (wrapper == NULL) {\n            wrapper = createWrapper();\n        }\n        return wrapper->wrappedObject;\n    }\n\n    virtual ~ThreadLocal() {\n        ObjectWrapper<T> *wrapper = getWrapper();\n        if (wrapper != NULL) {\n            wrapper->threadLocalObj->onDestroy(&wrapper->wrappedObject);\n            delete wrapper;\n        }\n        pthread_key_delete(pthreadKey);\n    }\n\n    virtual void onCreate(T *value) {\n        //do nothing by default;\n        //!!!!!shall NOT access anything other than VALUE!!!!!\n        *value = _defaultValue;\n    }\n\n    virtual void onDestroy(T *value) {\n        //do nothing by default;\n        //!!!!!shall NOT access anything other than VALUE!!!!!\n    }\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/thread/ThreadPool.cpp",
    "content": "#include <exception>\r\n#include \"ThreadPool.h\"\r\n#include \"Task.h\"\r\n\r\nusing namespace std;\r\n\r\nnamespace nacos{\r\nDummyTask ThreadPool::_dummyTask;\r\n\r\nvoid *ThreadPool::runInThread(void *param) {\r\n    ThreadPool *thisobj = (ThreadPool *) param;\r\n\r\n    log_debug(\"ThreadPool::runInThread()\\n\");\r\n    while (!thisobj->_stop) {\r\n        Task *t = thisobj->take();\r\n        NacosString taskName = t->getTaskName();\r\n        log_debug(\"Thread got task:%s\\n\", taskName.c_str());\r\n        try {\r\n            t->run();\r\n        }\r\n        catch (exception &e) {\r\n            log_error(\"Exception happens when executing:\\n\");\r\n            log_error(\"Thread pool Name:%s Task name:%s\\n\", thisobj->_poolName.c_str(), taskName.c_str());\r\n            log_error(\"Raison:%s\", e.what());\r\n        }\r\n        catch (...) {\r\n            log_error(\"Unknown exception happens when executing:\\n\");\r\n            log_error(\"Thread pool Name:%s Task name:%s\\n\", thisobj->_poolName.c_str(), taskName.c_str());\r\n            throw;\r\n        }\r\n        log_debug(\"Thread finished task:%s without problem\\n\", taskName.c_str());\r\n    }\r\n\r\n    return NULL;\r\n}\r\n\r\nTask *ThreadPool::take() {\r\n    LockGuard _lockGuard(_lock);\r\n    while (_taskList.empty() && !_stop) {\r\n        _NotEmpty.wait();\r\n    }\r\n\r\n    if (!_taskList.empty()) {\r\n        Task *curTask = _taskList.front();\r\n        _taskList.pop_front();\r\n        _NotFull.notify();\r\n\r\n        return curTask;\r\n    }\r\n\r\n    return &_dummyTask;\r\n};\r\n\r\nvoid ThreadPool::put(Task *t) {\r\n    {\r\n        LockGuard _lockGuard(_lock);\r\n\r\n        log_debug(\"ThreadPool:::::taskList:%d poolSize:%d stop:%d\\n\", _taskList.size(), _poolSize, _stop);\r\n        while (!(_taskList.size() < _poolSize) && !_stop) {\r\n            _NotFull.wait();\r\n        }\r\n\r\n        if (!_stop) {\r\n            _taskList.push_back(t);\r\n            _NotEmpty.notify();\r\n            return;\r\n        }\r\n    }\r\n\r\n    //The thread pool is stopped, we need to run it locally\r\n    log_debug(\"Running locally since the threadpool is stopped\\n\");\r\n    t->run();\r\n};\r\n\r\nvoid ThreadPool::start() {\r\n    log_warn(\"ThreadPool::start() start\\n\");\r\n    if (!_stop) {\r\n        log_warn(\"Thread pool named '%s' is started multiple times\\n\", _poolName.c_str());\r\n        return;\r\n    }\r\n\r\n    _stop = false;\r\n    for (size_t i = 0; i < _poolSize; i++) {\r\n        Thread *currentThread = new Thread(_poolName + \"-poolthread-\" + NacosStringOps::valueOf(i), runInThread, this);\r\n        _threads.push_back(currentThread);\r\n        currentThread->start();\r\n    }\r\n};\r\n\r\nvoid ThreadPool::stop() {\r\n    if (_stop) {\r\n        return;\r\n    }\r\n\r\n    _stop = true;\r\n    {\r\n        LockGuard _lockGuard(_lock);\r\n        _NotEmpty.notifyAll();\r\n        _NotFull.notifyAll();\r\n    }\r\n\r\n    for (std::list<Thread *>::iterator it = _threads.begin(); it != _threads.end(); it++) {\r\n        (*it)->join();\r\n        delete *it;\r\n    }\r\n\r\n    _threads.clear();\r\n};\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/thread/ThreadPool.h",
    "content": "#ifndef __THREAD_POOL_H_\n#define __THREAD_POOL_H_\n\n#include <list>\n#include <deque>\n#include \"Thread.h\"\n#include \"Task.h\"\n#include \"NacosString.h\"\n#include \"src/thread/Mutex.h\"\n\nnamespace nacos{\nclass DummyTask : public Task {\npublic:\n    DummyTask() { setTaskName(\"DummyTask\"); };\n\n    void run() {};\n};\n\nclass ThreadPool {\nprivate:\n    NacosString _poolName;\n    std::deque<Task *> _taskList;\n    Mutex _lock;\n    Condition _NotEmpty;\n    Condition _NotFull;\n    static DummyTask _dummyTask;\n\n    static void *runInThread(void *param);\n\n    ThreadPool() :\n            _poolName(\"CannotBeCreated\"), _NotEmpty(_lock), _NotFull(_lock), _stop(true), _poolSize(0) {};\nprotected:\n    std::list<Thread *> _threads;\n    volatile bool _stop;\n    size_t _poolSize;\npublic:\n    ThreadPool(const NacosString &poolName, size_t poolSize) :\n            _poolName(poolName), _NotEmpty(_lock), _NotFull(_lock), _stop(true), _poolSize(poolSize) {\n    };\n\n    ThreadPool(size_t poolSize) :\n            _poolName(\"NacosCliWorkerThread\"), _NotEmpty(_lock), _NotFull(_lock), _stop(true), _poolSize(poolSize) {\n    };\n\n    virtual ~ThreadPool() {};\n\n    Task *take();\n\n    void put(Task *t);\n\n    virtual void start();\n\n    virtual void stop();\n};\n\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/thread/Tid.cpp",
    "content": "#include \"src/thread/Tid.h\"\n\n#if defined(__CYGWIN__) || defined(MS_WINDOWS)\n//TODO:for windows/cygwin\n\n#elif defined(linux)\n//for linux\n//solved in header file\n\n#elif defined(__APPLE__) && defined(__MACH__)\n//Mac OS code goes here\n#include<pthread.h>\nTID_T gettidv1() {\n    TID_T tid;\n    pthread_threadid_np(NULL, &tid);\n\n    return tid;\n}\n#else\n//regard the system as an unix-like system\n//for linux solved in header file\n\n#endif//OS-specific code\n"
  },
  {
    "path": "src/thread/Tid.h",
    "content": "#ifndef __TID_HELPER_H_\n#define __TID_HELPER_H_\n#if defined(__CYGWIN__) || defined(MS_WINDOWS)\n//TODO:for windows/cygwin\n#include <sys/syscall.h>\n#include <unistd.h>\n#define TID_T pid_t\n#define gettidv1() syscall(__NR_gettid)\n\n#elif defined(linux) || defined(LINUX)\n//for linux\n#include <sys/syscall.h>\n#include <unistd.h>\n#define TID_T pid_t\n#define gettidv1() syscall(__NR_gettid)\n//#define gettidv2() syscall(SYS_gettid)\n\n#elif defined(__APPLE__) && defined(__MACH__)\n//Mac OS code goes here\n#define TID_T unsigned long long\nTID_T gettidv1();\n\n#else\n//regard the system as an unix-like system\n#include <sys/syscall.h>\n#include <unistd.h>\n#define TID_T pid_t\n#define gettidv1() syscall(__NR_gettid)\n\n#endif//OS-specific code\n\n#endif//HEADER_GUARD\n"
  },
  {
    "path": "src/utils/ConfigParserUtils.cpp",
    "content": "//\n// Created by liuhanyu on 2021/1/9.\n//\n\n#include <vector>\n#include \"ConfigParserUtils.h\"\n#include \"src/config/IOUtils.h\"\n#include \"src/utils/ParamUtils.h\"\n#include \"constant/ConfigConstant.h\"\nusing namespace std;\n\nnamespace nacos {\n\nProperties ConfigParserUtils::parseConfigFile(const NacosString &file) NACOS_THROW(NacosException) {\n    Properties parsedConfig;\n    NacosString confContent = IOUtils::readStringFromFile(file, NULLSTR);//TODO: add encoding support\n\n    vector <NacosString> configList;\n    ParamUtils::Explode(configList, confContent, ConfigConstant::CONFIG_NEXT_LINE);\n\n    int line = 0;\n    for (vector<NacosString>::iterator it = configList.begin();\n         it != configList.end(); it++) {\n        line++;\n        NacosString trimmedLine = ParamUtils::trim(*it);\n        if (ParamUtils::isBlank(trimmedLine)) {\n            continue;\n        }\n\n        if (trimmedLine[0] == '#') {\n            //skip comment\n            continue;\n        }\n\n        if (it->find(ConfigConstant::CONFIG_KV_SEPARATOR) == std::string::npos) {\n            throw MalformedConfigException(file, \" no '=' found at line \" + NacosStringOps::valueOf(line));\n        }\n\n        vector <NacosString> configKV;\n        ParamUtils::Explode(configKV, *it, ConfigConstant::CONFIG_KV_SEPARATOR);\n        //k = v\n        NacosString key = ParamUtils::trim(configKV[0]);\n        if (ParamUtils::isBlank(key)) {\n            throw MalformedConfigException(file, \" key is blank at \" + NacosStringOps::valueOf(line));\n        }\n\n        if (configKV.size() == 1) {\n            parsedConfig[key] = NULLSTR;\n        } else {\n            parsedConfig[key] = configKV[1];\n        }\n    }\n\n    return parsedConfig;\n}\n\n}"
  },
  {
    "path": "src/utils/ConfigParserUtils.h",
    "content": "//\n// Created by liuhanyu on 2021/1/9.\n//\n\n#ifndef NACOS_SDK_CPP_CONFIGPARSERUTILS_H\n#define NACOS_SDK_CPP_CONFIGPARSERUTILS_H\n#include \"Properties.h\"\n#include \"NacosExceptions.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos {\n\nclass ConfigParserUtils {\npublic:\n    static Properties parseConfigFile(const NacosString &file) NACOS_THROW(NacosException);\n\n};\n\n}\n\n#endif //NACOS_SDK_CPP_CONFIGPARSERUTILS_H\n"
  },
  {
    "path": "src/utils/DirUtils.cpp",
    "content": "#include <unistd.h>\n#include <sys/types.h>\n#include <pwd.h>\n#include \"src/utils/DirUtils.h\"\n\n#if defined(__CYGWIN__) || defined(MS_WINDOWS)\n#define PATH_MAX 260\n#elif defined(linux)\n#include <linux/limits.h>\n#elif defined(FreeBSD)\n#include <sys/syslimits.h>\n#else\n\n//we don't know how to handle this situation, check if it's defined\n//the is not necessarily an issue, actually in most cases it will just work\n#warning \"Unknown system or arch, trying fallback strategy. Please check if the compilation is correct\"\n#ifndef PATH_MAX\n#define PATH_MAX 260\n#endif\n\n#endif\n\n\nnamespace nacos{\nNacosString DirUtils::getHome() {\n    struct passwd *pw = getpwuid(getuid());\n    NacosString homedir = pw->pw_dir;\n    return homedir;\n}\n\nNacosString DirUtils::getCwd() {\n    char cwd[PATH_MAX];\n    NacosString cwds;\n    if (getcwd(cwd, sizeof(cwd)) != NULL) {\n        cwds = cwd;\n        return cwds;\n    }\n\n    return NULLSTR;\n}\n}//namespace nacos\n"
  },
  {
    "path": "src/utils/DirUtils.h",
    "content": "#ifndef __DIR_UTILS_H_\n#define __DIR_UTILS_H_\n\n#include \"NacosString.h\"\n\nnamespace nacos{\nclass DirUtils {\npublic:\n    static NacosString getHome();\n\n    static NacosString getCwd();\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/utils/Env.h",
    "content": "#include <stdlib.h>\n\nconst char* getEnv(const char* env) {\n    if (env == NULL) {\n        return NULL;\n    }\n    char* var = getenv(env);\n    return var;\n}"
  },
  {
    "path": "src/utils/GroupKey.h",
    "content": "#ifndef __GROUP_KEY_H_\n#define __GROUP_KEY_H_\n\n#include \"NacosString.h\"\n#include \"src/utils/url.h\"\n\n/*\n * Copyright 1999-2018 Alibaba Group Holding Ltd.\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.\n */\n\n/**\n * Synthesize the form of dataId+groupId. Escapes reserved characters in dataId and groupId.\n *\n * @author Nacos\n */\nnamespace nacos{\nclass GroupKey {\npublic:\n    static NacosString getKey(const NacosString &dataId, const NacosString &group) {\n        //DataID+GroupId\n        return urlencode(dataId) + \"+\" + urlencode(group);\n    }\n\n    static NacosString getKeyTenant(const NacosString &dataId, const NacosString &group, const NacosString &tenant) {\n        //DataID+GroupId\n        NacosString key = getKey(dataId, group);\n\n        if (!isNull(tenant)) {\n            key = key + \"+\" + urlencode(tenant);\n        }\n        return key;\n    }\n\n    /*static NacosString getKey(const NacosString &dataId, const NacosString &group, const NacosString &datumStr)\n    {\n        //DataID+GroupId+datumStr\n        return urlencode(dataId) + \"+\" + urlencode(group) + \"+\" + urlencode(datumStr);\n    }*/\n\n    /*static public NacosString[] parseKey(NacosString groupKey) {\n        StringBuilder sb = new StringBuilder();\n        NacosString dataId = null;\n        NacosString group = null;\n        NacosString tenant = null;\n\n        for (int i = 0; i < groupKey.length(); ++i) {\n            char c = groupKey.charAt(i);\n            if ('+' == c) {\n                if (null == dataId) {\n                    dataId = sb.toString();\n                    sb.setLength(0);\n                } else if (null == group) {\n                    group = sb.toString();\n                    sb.setLength(0);\n                } else {\n                    throw new IllegalArgumentException(\"invalid groupkey:\" + groupKey);\n                }\n            } else if ('%' == c) {\n                char next = groupKey.charAt(++i);\n                char nextnext = groupKey.charAt(++i);\n                if ('2' == next && 'B' == nextnext) {\n                    sb.append('+');\n                } else if ('2' == next && '5' == nextnext) {\n                    sb.append('%');\n                } else {\n                    throw new IllegalArgumentException(\"invalid groupkey:\" + groupKey);\n                }\n            } else {\n                sb.append(c);\n            }\n        }\n\n        if (StringUtils.isBlank(group)) {\n            group = sb.toString();\n            if (group.length() == 0) {\n                throw new IllegalArgumentException(\"invalid groupkey:\" + groupKey);\n            }\n        } else {\n            tenant = sb.toString();\n            if (group.length() == 0) {\n                throw new IllegalArgumentException(\"invalid groupkey:\" + groupKey);\n            }\n        }\n\n        return new NacosString[] {dataId, group, tenant};\n    }*/\n\n    /**\n     * + -> %2B % -> %25\n     */\n    /*static void urlEncode(NacosString str, StringBuilder sb) {\n        for (int idx = 0; idx < str.length(); ++idx) {\n            char c = str.charAt(idx);\n            if ('+' == c) {\n                sb.append(\"%2B\");\n            } else if ('%' == c) {\n                sb.append(\"%25\");\n            } else {\n                sb.append(c);\n            }\n        }\n    }*/\n\n};\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "src/utils/NamingUtils.h",
    "content": "#ifndef __NAMING_UTILS_H_\n#define __NAMING_UTILS_H_\n\n#include <vector>\n#include \"NacosString.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"src/utils/ParamUtils.h\"\n\nnamespace nacos{\nclass NamingUtils {\npublic:\n    static NacosString getGroupedName(const NacosString &serviceName, const NacosString &groupName) {\n        return groupName + ConfigConstant::SERVICE_INFO_SPLITER + serviceName;\n    }\n\n    static NacosString getServiceName(const NacosString &serviceNameWithGroup) {\n        if (!ParamUtils::contains(serviceNameWithGroup, ConfigConstant::SERVICE_INFO_SPLITER)) {\n            return serviceNameWithGroup;\n        }\n        std::vector <NacosString> splittedNameNGroup;\n        ParamUtils::Explode(splittedNameNGroup, serviceNameWithGroup, ConfigConstant::SERVICE_INFO_SPLITER);\n        return splittedNameNGroup[1];\n    }\n\n    static NacosString getGroupName(const NacosString &serviceNameWithGroup) {\n        if (!ParamUtils::contains(serviceNameWithGroup, ConfigConstant::SERVICE_INFO_SPLITER)) {\n            return ConfigConstant::DEFAULT_GROUP;\n        }\n        std::vector <NacosString> splittedNameNGroup;\n        ParamUtils::Explode(splittedNameNGroup, serviceNameWithGroup, ConfigConstant::SERVICE_INFO_SPLITER);\n        return splittedNameNGroup[0];\n    }\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/utils/NetUtils.cpp",
    "content": "#include \"NetUtils.h\"\r\n#include <arpa/inet.h>\r\n#include <sys/socket.h>\r\n#include <netdb.h>\r\n#include <errno.h>\r\n#include <ifaddrs.h>\r\n#include <src/log/Logger.h>\r\n#include <string.h>\r\n#include <unistd.h>\r\n\r\n#define HOST_AND_LEN 250\r\n\r\nnamespace nacos{\r\n\r\nNacosString NetUtils::getHostIp() NACOS_THROW(NacosException){\r\n\r\n    struct ifaddrs *ifaddr, *ifa;\r\n    int s;\r\n    char host[NI_MAXHOST];\r\n\r\n    if (getifaddrs(&ifaddr) == -1)\r\n    {\r\n        throw NacosException(NacosException::UNABLE_TO_GET_HOST_IP, \"Failed to get IF address\");\r\n    }\r\n\r\n\r\n    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)\r\n    {\r\n        log_debug(\"iterating on iface=%s\\n\", ifa->ifa_name);\r\n        if (ifa->ifa_addr == NULL || !(ifa->ifa_addr->sa_family==AF_INET)) {\r\n            continue;\r\n        }\r\n\r\n        if((strcmp(ifa->ifa_name,\"lo\")==0)) {\r\n            continue;\r\n        }\r\n\r\n        s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);\r\n        if (s != 0) {\r\n            freeifaddrs(ifaddr);\r\n            throw NacosException(NacosException::UNABLE_TO_GET_HOST_IP, \"Failed to get IF address\");\r\n        }\r\n\r\n        log_debug(\"selected iface=%s ip=%s\\n\", ifa->ifa_name, host);\r\n        freeifaddrs(ifaddr);\r\n        return host;\r\n    }\r\n    //Usually the program will not run to here\r\n    throw NacosException(NacosException::UNABLE_TO_GET_HOST_IP, \"Failed to get IF address\");\r\n}\r\n\r\nNacosString NetUtils::getHostName() NACOS_THROW(NacosException)\r\n{\r\n    char hostname[HOST_AND_LEN];\r\n    \r\n    int res = gethostname(hostname, HOST_AND_LEN);\r\n    if (res == 0) {\r\n        return NacosString(hostname);\r\n    }\r\n\r\n    throw NacosException(NacosException::UNABLE_TO_GET_HOST_NAME, \"Failed to get hostname, errno = \" + NacosStringOps::valueOf(errno));\r\n}\r\n\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/utils/NetUtils.h",
    "content": "#ifndef __NET_UTILS_H_\n#define __NET_UTILS_H_\n\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"Compatibility.h\"\n\nnamespace nacos{\nclass NetUtils {\npublic:\n    //Get IP address (best guess)\n    static NacosString getHostIp() NACOS_THROW(NacosException);\n\n    //Get hostname\n    static NacosString getHostName() NACOS_THROW(NacosException);\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/utils/ParamUtils.h",
    "content": "#ifndef __PARMUTILS_H_\n#define __PARMUTILS_H_\n\n#include <map>\n#include <list>\n#include <vector>\n#include <assert.h>\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"constant/ConfigConstant.h\"\n\nnamespace nacos{\nclass ParamUtils {\npublic:\n    template<typename T>\n    static const T &getNthElem(const std::list <T> &parm, size_t i) {\n        assert(parm.size() > i);\n        typename std::list<T>::const_iterator it = parm.begin();\n        for (size_t skipper = 0; skipper < i; skipper++) {\n            it++;\n        }\n\n        return *it;\n    }\n\n    static NacosString trim(const NacosString &content) {\n        int start = 0;\n        int end = content.size() - 1;\n\n        while (start < end && isBlank(content[start])) {\n            start++;\n        }\n\n        while (start < end && isBlank(content[end])) {\n            end--;\n        }\n\n        return NacosString(content.substr(start, end - start + 1));\n    }\n\n    static NacosString null2defaultGroup(const NacosString &group) {\n        return (isNull(group)) ? ConfigConstant::DEFAULT_GROUP : ParamUtils::trim(group);\n    }\n\n    static void parseString2KeyGroupTenant(const NacosString &stringToParse, NacosString &dataId, NacosString &group,\n                                           NacosString &tenant) {\n        std::vector <NacosString> KGT;//KeyGroupTenant\n        Explode(KGT, stringToParse, ConfigConstant::WORD_SEPARATOR);\n        dataId = KGT[0];\n        group = KGT[1];\n        if (KGT.size() == 3)//with tenant\n        {\n            tenant = KGT[2];\n        } else {\n            tenant = NULLSTR;\n        }\n    }\n\n    static bool isBlank(char character) {\n        switch (character) {\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case '\\n':\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    static bool isBlank(const NacosString &content) {\n        //TODO:Apply ParamUtils.Java's logic to here, support whitespaces in other countries/zones\n        if (content.size() == 0) {\n            return true;\n        }\n\n        for (size_t i = 0; i < content.size(); i++) {\n            if (!isBlank(content[i]))\n                return false;\n        }\n\n        return true;\n    };\n\n    static bool isValid(const NacosString &content) {\n        return false;\n    };\n\n    static void\n    checkParam(const NacosString &dataId, const NacosString &group, const NacosString &content) NACOS_THROW(NacosException) {\n        if (isBlank(content)) {\n            throw NacosException(NacosException::CLIENT_INVALID_PARAM, \"content invalid\");\n        }\n    };\n\n    //A little trick here for NacosString constants\n    static void\n    Explode(std::vector <NacosString> &explodedList, const NacosString &stringToExplode, const NacosString &separator) {\n        size_t start_pos = 0;\n        size_t separator_len = separator.length();\n        size_t cur_pos = 0;\n        cur_pos = stringToExplode.find(separator, start_pos);\n\n        //break the string with separator\n        while (cur_pos != std::string::npos) {\n            NacosString cur_addr = stringToExplode.substr(start_pos, cur_pos - start_pos);\n            explodedList.push_back(cur_addr);\n            start_pos = cur_pos + separator_len;\n            cur_pos = stringToExplode.find(separator, start_pos);\n        }\n\n        //deal with the last string\n        NacosString last_addr = stringToExplode.substr(start_pos);\n        explodedList.push_back(last_addr);\n    }\n\n    static void Explode(std::vector <NacosString> &explodedList, const NacosString &stringToExplode, char separator) {\n        size_t start_pos = 0;\n        size_t cur_pos = 0;\n        cur_pos = stringToExplode.find(separator, start_pos);\n\n        //break the string with separator\n        while (cur_pos != std::string::npos) {\n            NacosString cur_addr = stringToExplode.substr(start_pos, cur_pos - start_pos);\n            explodedList.push_back(cur_addr);\n            start_pos = cur_pos + 1;\n            cur_pos = stringToExplode.find(separator, start_pos);\n        }\n\n        //deal with the last string\n        NacosString last_addr = stringToExplode.substr(start_pos);\n        explodedList.push_back(last_addr);\n    }\n\n    static void Explode(std::list <NacosString> &explodedList, const NacosString &stringToExplode, char separator) {\n        size_t start_pos = 0;\n        size_t cur_pos = 0;\n        cur_pos = stringToExplode.find(separator, start_pos);\n\n        //break the string with separator\n        while (cur_pos != std::string::npos) {\n            NacosString cur_addr = stringToExplode.substr(start_pos, cur_pos - start_pos);\n            explodedList.push_back(cur_addr);\n            start_pos = cur_pos + 1;\n            cur_pos = stringToExplode.find(separator, start_pos);\n        }\n\n        //deal with the last string\n        NacosString last_addr = stringToExplode.substr(start_pos);\n        explodedList.push_back(last_addr);\n    }\n\n    //use ',' as separator by default\n    static NacosString Implode(const std::list <NacosString> &toImplode) {\n        return Implode(toImplode, ',');\n    }\n\n    static NacosString Implode(const std::list <NacosString> &toImplode, char separator) {\n        NacosString implodedString;\n        for (std::list<NacosString>::const_iterator it = toImplode.begin();\n             it != toImplode.end(); /*it++ is within the for ... loop*/) {\n            implodedString += *it;\n            it++;\n            if (it != toImplode.end()) {\n                implodedString += \",\";\n            }\n        }\n\n        return implodedString;\n    }\n\n    //use ',' as default separator to serialize a map\n    static NacosString Implode(const std::map <NacosString, NacosString> &toImplode) {\n        return Implode(toImplode, ',');\n    }\n\n    static NacosString Implode(const std::map <NacosString, NacosString> &toImplode, char separator) {\n        NacosString implodedString;\n        for (std::map<NacosString, NacosString>::const_iterator it = toImplode.begin(); it != toImplode.end(); it++) {\n            implodedString += it->first + \"=\" + it->second;\n            if (it != toImplode.end()) {\n                implodedString += \",\";\n            }\n        }\n\n        return implodedString;\n    }\n\n    static bool contains(const NacosString &haystack, char needle) {\n        if (haystack.find(needle) != std::string::npos) {\n            return true;\n        }\n\n        return false;\n    }\n\n    static bool contains(const NacosString &haystack, const NacosString &needle) {\n        if (haystack.find(needle) != std::string::npos) {\n            return true;\n        }\n\n        return false;\n    }\n\n    static void addKV(std::list<NacosString> &list, const NacosString &key, const NacosString &value) {\n        list.push_back(key);\n        list.push_back(value);\n    }\n\n    static NacosString toLower(const NacosString &str) {\n        NacosString lowerCaseString;\n        for (NacosString::const_iterator it = str.begin(); it != str.end(); it++) {\n            lowerCaseString.push_back(tolower(*it));\n        }\n\n        return lowerCaseString;\n    }\n\n    static bool equals_ic(const NacosString &str1, const NacosString &str2) {\n\n        NacosString lcase_str1 = toLower(str1);\n        NacosString lcase_str2 = toLower(str2);\n\n        return lcase_str1 == lcase_str2;\n    }\n\n    static const NacosString &findByKey(const std::list <NacosString> &hayStack, const NacosString &needleKey) {\n        for (std::list<NacosString>::const_iterator it = hayStack.begin(); it != hayStack.end(); it++) {\n            if (*it == needleKey) {\n                it++;\n                return *it;\n            }\n        }\n\n        return NacosStringOps::nullstr;\n    }\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/utils/RandomUtils.cpp",
    "content": "#include <unistd.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"src/utils/RandomUtils.h\"\n\nnamespace nacos{\nint RandomUtils::fd;\n\nThreadLocal<bool> RandomUtils::initedForThisThread(false);\n\nvoid RandomUtils::Init() {\n    fd = open(\"/dev/urandom\", O_RDONLY);\n}\n\nvoid RandomUtils::DeInit() {\n    if (fd != 0) {\n        close(fd);\n        fd = 0;\n    }\n}\n\nsize_t RandomUtils::getRandomBuffer(void *dest, size_t size) {\n    size_t bytes_read = 0;\n    while (bytes_read < size)\n    {\n        bytes_read += read(fd, (char*)dest + bytes_read, size - bytes_read);\n    }\n\n    return bytes_read;\n}\n\nint RandomUtils::random_inner(){\n    if (!initedForThisThread.get()){\n        srand(time(NULL));\n        initedForThisThread.set(true);\n    }\n    return rand();\n}\n\nint RandomUtils::random(int begin, int end) NACOS_THROW (NacosException) {\n    //sanity check\n    if (begin == end || begin > end) {\n        throw NacosException(NacosException::INVALID_PARAM, \"end must be greater than begin\");\n    }\n    long offset = random_inner() % (end - begin + 1);\n    return begin + offset;\n}\n}//namespace nacos"
  },
  {
    "path": "src/utils/RandomUtils.h",
    "content": "#ifndef __RND_UTILS_H_\n#define __RND_UTILS_H_\n\n#include \"NacosExceptions.h\"\n#include \"src/thread/ThreadLocal.h\"\n#include \"Compatibility.h\"\n\n/**\n * RandomUtils\n *\n * @author Liu, Hanyu\n * get random buffer from /dev/urandom\n * and helper functions to get random random number\n */\n\nnamespace nacos{\nclass RandomUtils {\nprivate:\n    static int fd;\n\n    static int random_inner();\n\n    static ThreadLocal<bool> initedForThisThread;\npublic:\n\n    static void Init();\n\n    static void DeInit();\n\n    static size_t getRandomBuffer(void *dest, size_t size);\n\n    /**\n     * generates a random number ranges from begin to end (including the begin and the end)\n     *\n     * @param begin begin of the range (inclusive)\n     * @param end   end of the range   (inclusive)\n     * @return a long random number\n     * @throw (NacosException) if begin >= end\n     */\n    static int random(int begin, int end) NACOS_THROW(NacosException);\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/utils/SequenceProvider.h",
    "content": "#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include \"NacosString.h\"\n#include \"NacosExceptions.h\"\n#include \"thread/AtomicInt.h\"\n#include \"src/thread/Mutex.h\"\n#include \"src/config/IOUtils.h\"\n\nnamespace nacos\n{\n\ntemplate<typename T>\nclass SequenceProvider {\nprivate:\n    NacosString _fileName;\n    AtomicInt<T> _current;\n    Mutex _acquireMutex;\n    T _nr_to_preserve;\n    T _initSequence;\n    volatile T _hwm;//high water mark\n\n    void ensureWrite(int fd, T data) {\n        size_t bytes_written = 0;\n        while (bytes_written < sizeof(T)) {\n            bytes_written += write(fd, (char*)&data + bytes_written, sizeof(T) - bytes_written);\n        }\n    }\n\n    T preserve() {\n        T current;\n        int fd;\n        bool newFile = false;\n        if (IOUtils::checkNotExistOrNotFile(_fileName)) {\n            newFile = true;\n        }\n        mode_t mode = S_IRUSR | S_IWUSR | S_IRWXG | S_IWGRP;\n        fd = open(_fileName.c_str(), O_RDWR | O_CREAT, mode);\n        if (fd <= 0) {\n            throw new NacosException(NacosException::UNABLE_TO_OPEN_FILE, _fileName);\n        }\n        \n        if (newFile) {\n            ensureWrite(fd, _initSequence);\n            lseek(fd, 0, SEEK_SET);//read from the beginning\n        }\n\n        size_t bytes_read = 0;\n        while (bytes_read < sizeof(T))\n        {\n            bytes_read += read(fd, (char*)&current + bytes_read, sizeof(T) - bytes_read);\n        }\n        lseek(fd, 0, SEEK_SET);//write from the beginning\n\n        ensureWrite(fd, current + _nr_to_preserve);\n        close(fd);\n        _hwm = current + _nr_to_preserve;\n        return current;\n    };\npublic:\n    SequenceProvider(const NacosString &fileName, T initSequence, T nr_to_preserve) {\n        _fileName = fileName;\n        _initSequence = initSequence;\n        _nr_to_preserve = nr_to_preserve;\n        _current.set(preserve());\n    };\n\n    T next(int step = 1) {\n        T res = _current.getAndInc(step);\n        while (res >= _hwm) {\n            _acquireMutex.lock();\n            if (res >= _hwm) {\n                preserve();\n            }\n            _acquireMutex.unlock();\n        }\n        return res;\n    };\n};\n\n} // namespace nacos\n"
  },
  {
    "path": "src/utils/TimeUtils.cpp",
    "content": "#include <stddef.h>\n#include \"src/utils/TimeUtils.h\"\n\nnamespace nacos{\nint64_t TimeUtils::getCurrentTimeInMs() {\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n\n    return tv.tv_sec * 1000 + tv.tv_usec / 1000;\n}\n\nvoid TimeUtils::getCurrentTimeInStruct(struct timeval &tv) {\n    gettimeofday(&tv, NULL);\n}\n\n}//namespace nacos\n"
  },
  {
    "path": "src/utils/TimeUtils.h",
    "content": "#ifndef __TIME_UTILS_H_\n#define __TIME_UTILS_H_\n\n#include <stdint.h>\n#include <sys/time.h>\n\nnamespace nacos{\nclass TimeUtils {\npublic:\n    static int64_t getCurrentTimeInMs();\n    static void getCurrentTimeInStruct(struct timeval &tv);\n\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/utils/UuidUtils.cpp",
    "content": "#include <unistd.h>\r\n#include <sys/stat.h>\r\n#include <fcntl.h>\r\n#include <stdio.h>\r\n\r\n#include \"src/utils/UuidUtils.h\"\r\n#include \"src/utils/RandomUtils.h\"\r\n\r\nnamespace nacos{\r\nvoid UuidUtils::Init() {\r\n}\r\n\r\nvoid UuidUtils::DeInit() {\r\n}\r\n\r\nNacosString UuidUtils::generateUuid() {\r\n    char random_num[UUID_LEN_BYTES];\r\n    char str_buffer[33];\r\n\r\n    //an UUID has 128 bits(16 bytes), so we need to get 16 bytes from the urandom\r\n    RandomUtils::getRandomBuffer(random_num, UUID_LEN_BYTES);\r\n\r\n    int32_t *val_ptr = (int32_t *) random_num;\r\n    snprintf(str_buffer, sizeof(str_buffer), \"%08X%08X%08X%08X\", val_ptr[0], val_ptr[1], val_ptr[2], val_ptr[3]);\r\n\r\n    NacosString uuid = str_buffer;\r\n    return uuid;\r\n}\r\n\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/utils/UuidUtils.h",
    "content": "#ifndef __UUID_UTILS_H_\n#define __UUID_UTILS_H_\n\n#include \"NacosString.h\"\n\n#define UUID_LEN_BYTES 16\n\n/**\n * UuidUtils\n *\n * @author yzz-ihep\n * Generates UUID from /dev/urandom\n */\n\nnamespace nacos{\nclass UuidUtils {\nprivate:\npublic:\n    static NacosString generateUuid();\n\n    static void Init();\n\n    static void DeInit();\n};\n}//namespace nacos\n\n#endif\n"
  },
  {
    "path": "src/utils/url.cpp",
    "content": "#include \"src/utils/url.h\"\r\n#include <curl/curl.h>\r\n\r\nnamespace nacos{\r\nNacosString urlencode(const NacosString &content) {\r\n    NacosString result;\r\n    CURL *curl = curl_easy_init();\r\n    char *output = NULL;\r\n    if (curl) {\r\n        output = curl_easy_escape(curl, content.c_str(), content.length());\r\n    }\r\n\r\n    if (output) {\r\n        result = output;\r\n        curl_free(output);\r\n    }\r\n\r\n    curl_easy_cleanup(curl);\r\n    return result;\r\n}\r\n\r\nNacosString urldecode(const NacosString &content) {\r\n    NacosString result;\r\n    CURL *curl = curl_easy_init();\r\n    char *output = NULL;\r\n    if (curl) {\r\n        output = curl_easy_unescape(curl, content.c_str(), content.length(), NULL);\r\n    }\r\n\r\n    if (output) {\r\n        result = output;\r\n        curl_free(output);\r\n    }\r\n\r\n    curl_easy_cleanup(curl);\r\n    return result;\r\n}\r\n}//namespace nacos\r\n"
  },
  {
    "path": "src/utils/url.h",
    "content": "#ifndef __URL_H_\n#define __URL_H_\n\n#include \"NacosString.h\"\n\nnamespace nacos{\nNacosString urlencode(const NacosString &content);\n\nNacosString urldecode(const NacosString &content);\n}//namespace nacos\n\n#endif"
  },
  {
    "path": "test/allinone.cpp",
    "content": "#include <iostream>\r\n#include <stdio.h>\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/init/Init.h\"\r\n#include \"src/log/Logger.h\"\r\n#include <list>\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testNormalHttpRequest();\r\n\r\nbool testNoServerRequest();\r\n\r\nbool testGetConfig();\r\n\r\nbool testGetConfigwithDefaultPort();\r\n\r\nbool testInvalidConfig();\r\n\r\nbool testDebug();\r\n\r\nbool testVaArgs();\r\n\r\nbool testVaArgs2();\r\n\r\nbool testlogPrint();\r\n\r\nbool testPublishConfig();\r\n\r\nbool testStringEqual();\r\n\r\nbool testAddListener();\r\n\r\nbool testReadWriteFile();\r\n\r\nbool testGetFileSize();\r\n\r\nbool testFileExists();\r\n\r\nbool testCreateAndRemove();\r\n\r\nbool testCleanDirectory();\r\n\r\nbool testSaveSnapshot();\r\n\r\nbool testCleanTestenvCacheAndGetTestenv();\r\n\r\nbool testCleanPrdCacheAndGetPrdenv();\r\n\r\nbool testCleanAllCache();\r\n\r\nbool testMD5();\r\n\r\nbool testURLEncodeAndDecode();\r\n\r\nbool testStringExplode();\r\n\r\nbool testStringExplode2();\r\n\r\nbool testNamingProxySmokeTest();\r\n\r\nbool testNamingServiceRegister();\r\n\r\nbool testRapidJsonIntroduce();\r\n\r\nbool testSerialize();\r\n\r\nbool testThreadSmoke();\r\n\r\nbool testThreadPoolSmoke();\r\n\r\nbool testString2ServiceInfo();\r\n\r\nbool testMalformedJson2ServiceInfo();\r\n\r\nbool testMalformedDouble2ServiceInfo();\r\n\r\nbool testLackcacheMillisServiceInfo();\r\n\r\nbool testGetAllInstances();\r\n\r\nbool testListeningKeys();\r\n\r\nbool testAppConfigManager();\r\n\r\nbool testServerListManager();\r\n\r\nbool testDeleteConfig();\r\n\r\nbool testEndpointWithNamingProxy();\r\n\r\nbool testUUID();\r\n\r\nbool testUUIDMT();\r\n\r\nbool testListenService();\r\n\r\nbool testGetServiceNames();\r\n\r\nbool testInstanceSelectors();\r\n\r\nbool testRandomByWeightSelector();\r\n\r\nbool testThreadLocal();\r\n\r\nbool testThreadLocalPtr();\r\n\r\nbool testThreadLocalPtrWithInitializer();\r\n\r\nbool testMaintainGetService();\r\n\r\nbool testMaintainUpdateService();\r\n\r\nbool testMaintainCreateService();\r\n\r\nbool testMaintainUpdateInstance();\r\n\r\nbool testPublishConfigWithHttpPrefix();\r\n\r\nbool testRemoveKeyBeingWatched();\r\n\r\nbool testGetHostIp();\r\n\r\nbool testDelayedThread();\r\n\r\nbool testDelayedThread2();\r\n\r\nbool testNamingServiceAndDeRegisterActively();\r\n\r\nbool testThreadPoolConcurrentWithAtomicCounter();\r\n\r\nbool testSequenceProvider();\r\n\r\nbool testHMACSHA1();\r\n\r\nbool testSubscribeAlotOfServices();\r\n\r\nTestData disabledTestList[] =\r\nTEST_ITEM_START\r\nTEST_ITEM_END\r\n\r\nTestData\r\ntestList[] =\r\nTEST_ITEM_START\r\n        TEST_ITEM(\"Normal http test\", testNormalHttpRequest)\r\n        TEST_ITEM(\"No server request, should fail\", testNoServerRequest)\r\n        TEST_ITEM(\"Publish config to server\", testPublishConfig)\r\n        TEST_ITEM(\"Get config from server\", testGetConfig)\r\n        TEST_ITEM(\"Get config from server (with default port)\", testGetConfigwithDefaultPort)\r\n        TEST_ITEM(\"Connect the server with invalid config, should throw an exception\", testInvalidConfig)\r\n        TEST_ITEM(\"Test printing logs\", testDebug)\r\n        TEST_ITEM(\"Delete config from server\", testDeleteConfig)\r\n        TEST_ITEM(\"Test printing logs with va_args\", testVaArgs)\r\n        TEST_ITEM(\"Test printing logs with va_args2\", testVaArgs2)\r\n        TEST_ITEM(\"Test printing logs\", testlogPrint)\r\n        TEST_ITEM(\"Test for string characteristics\", testStringEqual)\r\n        TEST_ITEM(\"Read&Write file test\", testReadWriteFile)\r\n        TEST_ITEM(\"GetFileSize, should work well\", testGetFileSize)\r\n        TEST_ITEM(\"Test get instances with predicate(testRandomByWeightSelector)\", testRandomByWeightSelector)\r\n        TEST_ITEM(\"Check whether file exists or not\", testFileExists)\r\n        TEST_ITEM(\"Create&Remove file\", testCreateAndRemove)\r\n        TEST_ITEM(\"Create a directory with subdirectories, and clean it\", testCleanDirectory)\r\n        TEST_ITEM(\"Save snapshot\", testSaveSnapshot)\r\n        TEST_ITEM(\"Save cache in test and prod env, then clean test env, should only get config from prod env\", testCleanTestenvCacheAndGetTestenv)\r\n        TEST_ITEM(\"Save cache in test and prod env, then clean prod env, should only get config from test env\", testCleanPrdCacheAndGetPrdenv)\r\n        TEST_ITEM(\"Save cache in test and prod env, then clean all, should not get any data\", testCleanAllCache)\r\n        TEST_ITEM(\"Test MD5\", testMD5)\r\n        TEST_ITEM(\"Endpoint function test, get available nacos server from endpoint\", testEndpointWithNamingProxy)\r\n        TEST_ITEM(\"Test urlencode/urldecode of libcurl\", testURLEncodeAndDecode)\r\n        TEST_ITEM(\"Test Config Listener function for nacos\", testAddListener)\r\n        TEST_ITEM(\"Test basic function of NamingProxy's registerService\", testNamingProxySmokeTest)\r\n        TEST_ITEM(\"Check whether rapidjson is introduced into the project successfully\", testRapidJsonIntroduce)\r\n        TEST_ITEM(\"Check if the serialization succeeds\", testSerialize)\r\n        TEST_ITEM(\"Smoke test for Thread\", testThreadSmoke)\r\n        TEST_ITEM(\"Smoke test for ThreadPool\", testThreadPoolSmoke)\r\n        TEST_ITEM(\"Test basic function of NacosNamingService's registerService\", testNamingServiceRegister)\r\n        TEST_ITEM(\"Test serialization/deserialization of Business Object\", testString2ServiceInfo)\r\n        TEST_ITEM(\"Test get instances with predicate(Randomly)\", testInstanceSelectors)\r\n        TEST_ITEM(\"Test serialization/deserialization of malformed Business Object\", testMalformedJson2ServiceInfo)\r\n        TEST_ITEM(\"Test serialization/deserialization of malformed Business Object (Double)\", testMalformedDouble2ServiceInfo)\r\n        TEST_ITEM(\"Test serialization/deserialization of malformed Business Object (no cacheMillis)\", testLackcacheMillisServiceInfo)\r\n        TEST_ITEM(\"Register many services and get one\", testGetAllInstances)\r\n        TEST_ITEM(\"Listen to key and remove it from listening list\", testListeningKeys)\r\n        TEST_ITEM(\"Test explode function\", testStringExplode)\r\n        TEST_ITEM(\"Test explode function version 2 enhanced\", testStringExplode2)\r\n        TEST_ITEM(\"AppConfigManager smoke test\", testAppConfigManager)\r\n        TEST_ITEM(\"ServerListManager smoke test\", testServerListManager)\r\n        TEST_ITEM(\"Test UUID generation\", testUUID)\r\n        TEST_ITEM(\"Test UUID generation(Multi-thread)\", testUUIDMT)\r\n        TEST_ITEM(\"Register many services and get one\", testGetAllInstances)\r\n        TEST_ITEM(\"Subscribe & unsubscribe services\", testListenService)\r\n        TEST_ITEM(\"Test get all service names\", testGetServiceNames)\r\n        TEST_ITEM(\"Smoking test of ThreadLocal\", testThreadLocal)\r\n        TEST_ITEM(\"Smoking test of ThreadLocal(pointer)\", testThreadLocalPtr)\r\n        TEST_ITEM(\"Smoking test of ThreadLocal(pointer with initializer)\", testThreadLocalPtrWithInitializer)\r\n        TEST_ITEM(\"MaintainService: testMaintainGetService\", testMaintainGetService)\r\n        TEST_ITEM(\"MaintainService: testMaintainUpdateService\", testMaintainUpdateService)\r\n        TEST_ITEM(\"MaintainService: testMaintainCreateService\", testMaintainCreateService)\r\n        TEST_ITEM(\"MaintainService: testMaintainUpdateInstance\", testMaintainUpdateInstance)\r\n        TEST_ITEM(\"Test with address config containing http prefix\", testPublishConfigWithHttpPrefix)\r\n        TEST_ITEM(\"Test with address config containing http prefix\", testRemoveKeyBeingWatched)\r\n        TEST_ITEM(\"Get local machine's IP\", testGetHostIp)\r\n        TEST_ITEM(\"Test delayed task pool\", testDelayedThread)\r\n        TEST_ITEM(\"Test delayed task pool - multiple tasks triggered at the same time\", testDelayedThread2)\r\n        TEST_ITEM(\"Register a service instance and remove it actively\", testNamingServiceAndDeRegisterActively)\r\n        TEST_ITEM(\"thread pool with concurrent add & atomic operation\", testThreadPoolConcurrentWithAtomicCounter)\r\n        TEST_ITEM(\"Test sequence provider\", testSequenceProvider)\r\n        TEST_ITEM(\"Test Message digest algorithm - HMACSHA1\", testHMACSHA1)\r\n        TEST_ITEM(\"Test subscribe a lot of services, bugfix #101\", testSubscribeAlotOfServices)\r\nTEST_ITEM_END\r\n\r\nint main() {\r\n    Init::doInit();\r\n    list<TestData *> failed_list;\r\n    cout << \"Please start a nacos server listening on port 8848 in this machine first.\" << endl;\r\n    cout << \"And when the server is ready, press any key to start the test.\" << endl;\r\n    getchar();\r\n    int nr_succ = 0, nr_fail = 0;\r\n    Logger::setLogLevel(DEBUG);\r\n    cout << \"BEGIN OF TESTS\" << endl;\r\n    cout << \"===========================\" << endl;\r\n    for (size_t i = 0; i < sizeof(testList) / sizeof(TestData); i++) {\r\n        TestData * curtest = &testList[i];\r\n        TESTFN testfunction = curtest->testFn;\r\n        cout << \"Testing \" << curtest->testName << \" ...\" << endl;\r\n        bool pass = testfunction();\r\n        if (!pass) {\r\n            cout << \"FAILED\" << endl;\r\n            failed_list.push_back(curtest);\r\n            nr_fail++;\r\n        } else {\r\n            cout << \"PASSED!\" << endl;\r\n            nr_succ++;\r\n        }\r\n        cout << \"===========================\" << endl;\r\n    }\r\n\r\n    if (!failed_list.empty()) {\r\n        cout << \"List of failed cases:\" << endl;\r\n        for (list<TestData*>::iterator it = failed_list.begin(); it != failed_list.end(); it++) {\r\n            cout << (*it)->testName << endl;\r\n        }\r\n        cout << \"===========================\" << endl;\r\n    }\r\n\r\n    cout << \"SUMMARY\" << endl;\r\n    cout << \"Total:\" << nr_succ + nr_fail << endl;\r\n    cout << \"Succ:\" << nr_succ << endl;\r\n    cout << \"Fail:\" << nr_fail << endl;\r\n    cout << \"===========================\" << endl;\r\n    return 0;\r\n}"
  },
  {
    "path": "test/testcase/AssertString.cpp",
    "content": "#include <iostream>\r\n#include \"NacosString.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\n//Use a special variable NULLSTR as null in Java to pass null parameter\r\n//But \"\" (zero-length string) will still be regarded as null\r\nbool testStringEqual() {\r\n    cout << \"In testStringEqual\" << endl;\r\n    NacosString s2 = \"\";\r\n    NacosString s3 = \"Nacos\";\r\n    SHOULD_BE_TRUE(isNull(NULLSTR), \"NULLSTR should be NULL\");\r\n    SHOULD_BE_TRUE(isNull(s2), \"\\\"\\\" should be NULL\");\r\n    SHOULD_BE_FALSE(isNull(s3), \"\\\"Nacos\\\" should not be NULL\");\r\n\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/DebugTest.cpp",
    "content": "#include \"src/log/Logger.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testDebug() {\r\n    log_print(DEBUG, \"print\\n\");\r\n    log_debug(\"debug\\n\");\r\n    log_info(\"info\\n\");\r\n    log_warn(\"warn\\n\");\r\n    log_error(\"error\\n\");\r\n    return true;\r\n}\r\n\r\nbool testVaArgs() {\r\n    //log_print(DEBUG, \"print\\n\",\"print\",\"print\");\r\n    log_debug(\"debug\\n\", \"debug\", \"debug\");\r\n    log_info(\"info\\n\", \"info\", \"info\");\r\n    log_warn(\"warn\\n\", \"warn\", \"warn\");\r\n    log_error(\"error\\n\", \"error\", \"error\");\r\n    return true;\r\n}\r\n\r\nbool testlogPrint() {\r\n    log_print(DEBUG, \"===>print %s %s %d\\n\", \"print\", \"print\", 9);\r\n    log_print(DEBUG, \"===>print %s %s %d\\n\", \"print\", \"print\", 9);\r\n    log_print(DEBUG, \"===>print %s %s %d\\n\", \"print\", \"print\", 9);\r\n    return true;\r\n}\r\n\r\nbool testVaArgs2() {\r\n    log_info(\"info %s %s\\n\", \"info\", \"info\");\r\n    log_print(DEBUG, \"print %s %s %d\\n\", \"print\", \"print\", 9);\r\n    log_debug(\"debug %s %s\\n\", \"debug\", \"debug\");\r\n    log_info(\"info %s %s\\n\", \"info\", \"info\");\r\n    log_warn(\"warn %s %s\\n\", \"warn\", \"warn\");\r\n    log_error(\"error %s %s %d %f\\n\", \"error\", \"error\", 999, 3.14);\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testAppConfigManager.cpp",
    "content": "#include <iostream>\n#include \"src/config/AppConfigManager.h\"\n#include \"src/utils/DirUtils.h\"\n#include \"constant/ConfigConstant.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testAppConfigManager() {\n    cout << \"in function testAppConfigManager\" << endl;\n\n    NacosString configFile = DirUtils::getCwd() + ConfigConstant::FILE_SEPARATOR + ConfigConstant::DEFAULT_CONFIG_FILE;\n    AppConfigManager appConfigManager(configFile);\n    appConfigManager.loadConfig(configFile);\n    Properties configs = appConfigManager.getAllConfig();\n    return true;\n}"
  },
  {
    "path": "test/testcase/testCache.cpp",
    "content": "#include <iostream>\r\n#include \"src/config/LocalSnapshotManager.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"NacosString.h\"\r\n#include \"ResourceGuard.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testSaveSnapshot() {\r\n    cout << \"in function testSaveSnapshot\" << endl;\r\n    Properties props;\r\n    AppConfigManager *appConfigManager = new AppConfigManager(props);\r\n    LocalSnapshotManager *localSnapshotManager = new LocalSnapshotManager(appConfigManager);\r\n    ResourceGuard<AppConfigManager> __guardCfg(appConfigManager);\r\n    ResourceGuard<LocalSnapshotManager> __guardCfgProcessor(localSnapshotManager);\r\n\r\n    localSnapshotManager->cleanAllSnapshot();\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"ConfigName=Value for FrontTenant\");\r\n    NacosString content = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    SHOULD_BE_TRUE(content == \"ConfigName=Value for FrontTenant\", \"Saved snapshot, read it again, should be the same\");\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"ConfigName=Value\");\r\n    content = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    SHOULD_BE_TRUE(content == \"ConfigName=Value\", \"Saved snapshot(No tenant), read it again, should be the same\");\r\n    return true;\r\n}\r\n\r\nbool testCleanTestenvCacheAndGetTestenv() {\r\n    cout << \"in function testCleanTestenvCacheAndGetTestenv\" << endl;\r\n    Properties props;\r\n    AppConfigManager *appConfigManager = new AppConfigManager(props);\r\n    LocalSnapshotManager *localSnapshotManager = new LocalSnapshotManager(appConfigManager);\r\n    ResourceGuard<AppConfigManager> __guardCfg(appConfigManager);\r\n    ResourceGuard<LocalSnapshotManager> __guardCfgProcessor(localSnapshotManager);\r\n    localSnapshotManager->cleanAllSnapshot();\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"Value for FrontTenant&Testenv\");\r\n    localSnapshotManager->saveSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"Value for FrontTenant&Prodenv\");\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"Value for Testenv\");\r\n    localSnapshotManager->saveSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"Value for Prodenv\");\r\n\r\n    NacosString cntfrontEndTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\",\r\n                                                                        \"FrontTenant\");\r\n    NacosString cntPrdFrontEnd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\",\r\n                                                                       \"FrontTenant\");\r\n    NacosString cntTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    NacosString cntPrd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n\r\n    SHOULD_BE_TRUE(cntfrontEndTest == \"Value for FrontTenant&Testenv\", \"Check settings for FrontTenant&Testenv\");\r\n    SHOULD_BE_TRUE(cntPrdFrontEnd == \"Value for FrontTenant&Prodenv\", \"Check settings for FrontTenant&Prodenv\");\r\n    SHOULD_BE_TRUE(cntTest == \"Value for Testenv\", \"Check settings for Testenv\");\r\n    SHOULD_BE_TRUE(cntPrd == \"Value for Prodenv\", \"Check settings for Prodenv\");\r\n\r\n    localSnapshotManager->cleanEnvSnapshot(\"Testenv\");\r\n    cntfrontEndTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    cntPrdFrontEnd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    cntTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    cntPrd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n\r\n    SHOULD_BE_TRUE(cntfrontEndTest == \"\", \"Testenv removed, Check settings for FrontTenant&Testenv\");\r\n    SHOULD_BE_TRUE(cntPrdFrontEnd == \"Value for FrontTenant&Prodenv\",\r\n                   \"Testenv removed, Check settings for FrontTenant&Prodenv\");\r\n    SHOULD_BE_TRUE(cntTest == \"\", \"Testenv removed, Check settings for Testenv\");\r\n    SHOULD_BE_TRUE(cntPrd == \"Value for Prodenv\", \"Testenv removed, Check settings for Prodenv\");\r\n    return true;\r\n}\r\n\r\nbool testCleanPrdCacheAndGetPrdenv() {\r\n    cout << \"in function testCleanPrdCacheAndGetPrdenv\" << endl;\r\n    Properties props;\r\n    AppConfigManager *appConfigManager = new AppConfigManager(props);\r\n    LocalSnapshotManager *localSnapshotManager = new LocalSnapshotManager(appConfigManager);\r\n    ResourceGuard<AppConfigManager> __guardCfg(appConfigManager);\r\n    ResourceGuard<LocalSnapshotManager> __guardCfgProcessor(localSnapshotManager);\r\n    localSnapshotManager->cleanAllSnapshot();\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"Value for FrontTenant&Testenv\");\r\n    localSnapshotManager->saveSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"Value for FrontTenant&Prodenv\");\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"Value for Testenv\");\r\n    localSnapshotManager->saveSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"Value for Prodenv\");\r\n\r\n    NacosString cntfrontEndTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\",\r\n                                                                        \"FrontTenant\");\r\n    NacosString cntPrdFrontEnd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\",\r\n                                                                       \"FrontTenant\");\r\n    NacosString cntTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    NacosString cntPrd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n\r\n    SHOULD_BE_TRUE(cntfrontEndTest == \"Value for FrontTenant&Testenv\", \"Check settings for FrontTenant&Testenv\");\r\n    SHOULD_BE_TRUE(cntPrdFrontEnd == \"Value for FrontTenant&Prodenv\", \"Check settings for FrontTenant&Prodenv\");\r\n    SHOULD_BE_TRUE(cntTest == \"Value for Testenv\", \"Check settings for Testenv\");\r\n    SHOULD_BE_TRUE(cntPrd == \"Value for Prodenv\", \"Check settings for Prodenv\");\r\n\r\n    localSnapshotManager->cleanEnvSnapshot(\"Prodenv\");\r\n    cntfrontEndTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    cntPrdFrontEnd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    cntTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    cntPrd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n\r\n    SHOULD_BE_TRUE(cntfrontEndTest == \"Value for FrontTenant&Testenv\",\r\n                   \"Prodenv removed, Check settings for FrontTenant&Testenv\");\r\n    SHOULD_BE_TRUE(cntPrdFrontEnd == \"\", \"Prodenv removed, Check settings for FrontTenant&Prodenv\");\r\n    SHOULD_BE_TRUE(cntTest == \"Value for Testenv\", \"Prodenv removed, Check settings for Testenv\");\r\n    SHOULD_BE_TRUE(cntPrd == \"\", \"Prodenv removed, Check settings for Prodenv\");\r\n    return true;\r\n}\r\n\r\nbool testCleanAllCache() {\r\n    cout << \"in function testCleanAllCache\" << endl;\r\n    Properties props;\r\n    AppConfigManager *appConfigManager = new AppConfigManager(props);\r\n    LocalSnapshotManager *localSnapshotManager = new LocalSnapshotManager(appConfigManager);\r\n    ResourceGuard<AppConfigManager> __guardCfg(appConfigManager);\r\n    ResourceGuard<LocalSnapshotManager> __guardCfgProcessor(localSnapshotManager);\r\n    localSnapshotManager->cleanAllSnapshot();\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"Value for FrontTenant&Testenv\");\r\n    localSnapshotManager->saveSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\",\r\n                                           \"Value for FrontTenant&Prodenv\");\r\n    localSnapshotManager->saveSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"Value for Testenv\");\r\n    localSnapshotManager->saveSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR, \"Value for Prodenv\");\r\n\r\n    NacosString cntfrontEndTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\",\r\n                                                                        \"FrontTenant\");\r\n    NacosString cntPrdFrontEnd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\",\r\n                                                                       \"FrontTenant\");\r\n    NacosString cntTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    NacosString cntPrd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n\r\n    SHOULD_BE_TRUE(cntfrontEndTest == \"Value for FrontTenant&Testenv\", \"Check settings for FrontTenant&Testenv\");\r\n    SHOULD_BE_TRUE(cntPrdFrontEnd == \"Value for FrontTenant&Prodenv\", \"Check settings for FrontTenant&Prodenv\");\r\n    SHOULD_BE_TRUE(cntTest == \"Value for Testenv\", \"Check settings for Testenv\");\r\n    SHOULD_BE_TRUE(cntPrd == \"Value for Prodenv\", \"Check settings for Prodenv\");\r\n\r\n    localSnapshotManager->cleanAllSnapshot();\r\n    cntfrontEndTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    cntPrdFrontEnd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", \"FrontTenant\");\r\n    cntTest = localSnapshotManager->getSnapshot(\"Testenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n    cntPrd = localSnapshotManager->getSnapshot(\"Prodenv\", \"DummyData\", \"BusinessGrp1\", NULLSTR);\r\n\r\n    SHOULD_BE_TRUE(cntfrontEndTest == \"\", \"cleanAllSnapshot(), Check settings for FrontTenant&Testenv\");\r\n    SHOULD_BE_TRUE(cntPrdFrontEnd == \"\", \"cleanAllSnapshot(), Check settings for FrontTenant&Prodenv\");\r\n    SHOULD_BE_TRUE(cntTest == \"\", \"cleanAllSnapshot(), Check settings for Testenv\");\r\n    SHOULD_BE_TRUE(cntPrd == \"\", \"cleanAllSnapshot(), Check settings for Prodenv\");\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testDelayedThreadPool.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <unistd.h>\n#include <stdio.h>\n#include \"src/thread/DelayedThreadPool.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"NacosExceptions.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass DelayedTask : public Task {\npublic:\n    DelayedThreadPool *executor;\n    uint64_t interval;// in MS\n    uint64_t last_exec_time;\n    DelayedTask() {\n        last_exec_time = 0;\n    }\n\n    void run() {\n        uint64_t now_ms = TimeUtils::getCurrentTimeInMs();\n        uint64_t interval_calc = 0;\n        if (last_exec_time != 0) {\n            interval_calc = now_ms - last_exec_time;\n        }\n        last_exec_time = now_ms;\n        executor->schedule(this,now_ms + interval);//interval/1000 secs later\n        if (executor == NULL) {\n            throw NacosException(NacosException::INVALID_CONFIG_PARAM, \"no executor\");\n        }\n        printf(\">>>>>>>>>>>>>>>>>>Task %s triggered, time =%llu (%llu), interval = %llu\\n\", getTaskName().c_str(), now_ms/1000, now_ms, interval_calc);\n\n        sleep(1);\n    }\n};\n\nbool testDelayedThread() {\n    cout << \"in function testDelayedThread\" << endl;\n\n    DelayedThreadPool dtp(\"testDPool\", 11);\n    dtp.start();\n    cout << \"create tasks\" << endl;\n\n    DelayedTask delayedTasks[10];\n\n    uint64_t now_ms = TimeUtils::getCurrentTimeInMs();\n    for (size_t i = 0; i < sizeof(delayedTasks) / sizeof(DelayedTask); i++) {\n        delayedTasks[i].executor = &dtp;\n        delayedTasks[i].interval = (i + 1) * 1000;\n        delayedTasks[i].setTaskName(\"DelayedTask-\" + NacosStringOps::valueOf(i));\n\n        dtp.schedule(&delayedTasks[i], now_ms);\n    }\n\n    sleep(20);\n\n    cout << \"call stop()\" << endl;\n    dtp.stop();\n    cout << \"end of test\" << endl;\n\n    return true;\n}\n\nbool testDelayedThread2() {\n    cout << \"in function testDelayedThread2 - multiple tasks triggered at the same time\" << endl;\n\n    DelayedThreadPool dtp(\"testDPool\", 11);\n    dtp.start();\n    cout << \"create tasks\" << endl;\n\n    DelayedTask delayedTasks[10];\n\n    uint64_t now_ms = TimeUtils::getCurrentTimeInMs();\n    for (size_t i = 0; i < sizeof(delayedTasks) / sizeof(DelayedTask); i++) {\n        delayedTasks[i].executor = &dtp;\n        delayedTasks[i].interval = 1000;\n        delayedTasks[i].setTaskName(\"DelayedTask-\" + NacosStringOps::valueOf(i));\n\n        dtp.schedule(&delayedTasks[i], now_ms);\n    }\n\n    sleep(20);\n\n    cout << \"call stop()\" << endl;\n    dtp.stop();\n    cout << \"end of test\" << endl;\n\n    return true;\n}\n"
  },
  {
    "path": "test/testcase/testDeleteConfig.cpp",
    "content": "#include <iostream>\r\n#include <stdio.h>\r\n#include \"factory/NacosFactoryFactory.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"ResourceGuard.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testDeleteConfig() {\r\n    cout << \"in function testDeleteConfig\" << endl;\r\n    Properties props;\r\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    ConfigService *n = factory->CreateConfigService();\r\n    ResourceGuard <ConfigService> _serviceFactory(n);\r\n    bool bSucc;\r\n    for (int i = 5; i < 50; i++) {\r\n        char key_s[200];\r\n        char val_s[200];\r\n        snprintf(key_s, sizeof(key_s), \"Key%d\", i);\r\n        snprintf(val_s, sizeof(val_s), \"v__%d\", i);\r\n\r\n        try {\r\n            bSucc = n->removeConfig(key_s, NULLSTR);\r\n        }\r\n        catch (NacosException &e) {\r\n            cout <<\r\n                 \"Request failed with curl code:\" << e.errorcode() << endl <<\r\n                 \"Reason:\" << e.what() << endl;\r\n            return false;\r\n        }\r\n        cout << \"Delete Key:\" << key_s << \" with value:\" << val_s << \" result:\" << bSucc << endl;\r\n    }\r\n\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testDeleteListenedKeys.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"listen/Listener.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyListener : public Listener {\nprivate:\n    int num;\npublic:\n    MyListener(int num) {\n        this->num = num;\n    }\n\n    void receiveConfigInfo(const NacosString &configInfo) {\n        cout << \"===================================\" << endl;\n        cout << \"Watcher\" << num << endl;\n        cout << \"Watched Key UPDATED:\" << configInfo << endl;\n        cout << \"===================================\" << endl;\n    }\n};\n\nbool testRemoveKeyBeingWatched() {\n    cout << \"in function testRemoveKeyBeingWatched\" << endl;\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    ADD_AUTH_INFO(props);\n    ADD_SPAS_INFO(props);\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    n->publishConfig(\"RemovedWhileWatching\", NULLSTR, \"dummyContent\");\n\n    MyListener *theListener = new MyListener(1);\n    n->addListener(\"RemovedWhileWatching\", NULLSTR, theListener);\n\n    sleep(2);\n    cout << \"remove key\" << endl;\n    n->removeConfig(\"RemovedWhileWatching\", NULLSTR);\n    sleep(2);\n    cout << \"set key\" << endl;\n    n->publishConfig(\"RemovedWhileWatching\", NULLSTR, \"dummyContent1\");\n    sleep(2);\n    cout << \"remove key\" << endl;\n    n->removeConfig(\"RemovedWhileWatching\", NULLSTR);\n    cout << \"Hold for 30 secs\" << endl;\n    sleep(30);\n    n->removeListener(\"RemovedWhileWatching\", NULLSTR, theListener);\n    cout << \"remove listener2\" << endl;\n    cout << \"test successful\" << endl;\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testEndpointWithNamingSvc.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <unistd.h>\n#include \"src/naming/NamingProxy.h\"\n#include \"src/naming/NacosNamingService.h\"\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"naming/Instance.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/UtilAndComs.h\"\n#include \"src/http/HTTPCli.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"constant/PropertyKeyConst.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testEndpointWithNamingProxy() {\n    cout << \"in function testEndpointWithNamingProxy\" << endl;\n    cout << \"For this test, please create an endpoint on your 80 port with a file in the following path:\" << endl;\n    cout << \"yourip:80/nacos/endpoint0\" << endl;\n    cout << \"And the content should be a list of ip:port separated with \\\\n the ip:port group points at a nacos server\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::ENDPOINT] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::ENDPOINT_PORT] = \"80\";\n    configProps[PropertyKeyConst::CONTEXT_PATH] = \"nacos\";\n    configProps[PropertyKeyConst::CLUSTER_NAME] = \"endpoint0\";\n\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(namingSvc);\n    Instance instance;\n    instance.clusterName = \"DefaultCluster\";\n    instance.ip = \"127.0.0.1\";\n    instance.port = 2333;\n    instance.instanceId = \"1\";\n    instance.ephemeral = true;\n\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n            instance.port = 2000 + i;\n            namingSvc->registerInstance(serviceName, instance);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return false;\n    }\n    cout << \"Keep the services for 30 secs...\" << endl;\n    sleep(30);\n    cout << \"Deregister the services\" << endl;\n    try {\n        for (int i = 0; i < 5; i++) {\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\n\n            namingSvc->deregisterInstance(serviceName, \"127.0.0.1\", 2000 + i);\n            sleep(1);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    cout << \"testNamingServiceRegister finished\" << endl;\n\n    return true;\n}\n"
  },
  {
    "path": "test/testcase/testGetAllInstances.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include <unistd.h>\r\n#include <list>\r\n#include \"src/naming/NamingProxy.h\"\r\n#include \"factory/NacosFactoryFactory.h\"\r\n#include \"naming/Instance.h\"\r\n#include \"constant/ConfigConstant.h\"\r\n#include \"constant/UtilAndComs.h\"\r\n#include \"src/http/HTTPCli.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/log/Logger.h\"\r\n#include \"NacosString.h\"\r\n#include \"Properties.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n#include \"ResourceGuard.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testGetAllInstances() {\r\n    cout << \"in function testGetAllInstances\" << endl;\r\n    Properties configProps;\r\n    ADD_AUTH_INFO(configProps);\r\n    ADD_SPAS_INFO(configProps);\r\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\r\n    configProps[PropertyKeyConst::NAMESPACE] = \"238e832b-d103-44c6-b618-d74da8c38b06\";\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    NamingService *namingSvc = factory->CreateNamingService();\r\n    ResourceGuard <NamingService> _guardService(namingSvc);\r\n\r\n    Instance instance;\r\n    instance.clusterName = \"DefaultCluster\";\r\n    instance.ip = \"127.0.0.1\";\r\n    instance.port = 2333;\r\n    instance.instanceId = \"1\";\r\n    instance.ephemeral = true;\r\n\r\n    try {\r\n        for (int i = 0; i < 10; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            instance.port = 2000 + i;\r\n            namingSvc->registerInstance(serviceName, instance);\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n    cout << \"wait for 5 secs\" << endl;\r\n    sleep(5);\r\n    list <Instance> instances = namingSvc->getAllInstances(\"TestNamingService1\");\r\n    cout << \"getAllInstances from server:\" << endl;\r\n    for (list<Instance>::iterator it = instances.begin();\r\n         it != instances.end(); it++) {\r\n        cout << \"Instance:\" << it->toString() << endl;\r\n    }\r\n\r\n    if (instances.size() != 1) {\r\n        cout << \"There should be only 1 instance for TestNamingService1\" << endl;\r\n        return false;\r\n    }\r\n\r\n    if (instances.front().port != 2001) {\r\n        cout << \"TestNamingService1's port should be 2001\" << endl;\r\n        return false;\r\n    }\r\n\r\n    if (instances.front().ip != \"127.0.0.1\") {\r\n        cout << \"TestNamingService1's ip should be 127.0.0.1\" << endl;\r\n        return false;\r\n    }\r\n\r\n    sleep(1);\r\n    try {\r\n        for (int i = 0; i < 3; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n\r\n            namingSvc->deregisterInstance(serviceName, \"127.0.0.1\", 2000 + i);\r\n            sleep(1);\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testGetConfig.cpp",
    "content": "#include <iostream>\r\n#include \"factory/NacosFactoryFactory.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"ResourceGuard.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testGetConfig() {\r\n    cout << \"in function testGetConfig\" << endl;\r\n    Properties props;\r\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    ConfigService *n = factory->CreateConfigService();\r\n    ResourceGuard <ConfigService> _serviceFactory(n);\r\n    NacosString ss = \"\";\r\n    try {\r\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\r\n    }\r\n    catch (NacosException &e) {\r\n        cout <<\r\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\r\n             \"Reason:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n    cout << ss << endl;\r\n\r\n    return true;\r\n}\r\n\r\nbool testGetConfigwithDefaultPort() {\r\n    cout << \"in function testGetConfigwithDefaultPort\" << endl;\r\n    Properties props;\r\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    ConfigService *n = factory->CreateConfigService();\r\n    ResourceGuard <ConfigService> _serviceFactory(n);\r\n    NacosString ss = n->getConfig(\"k\", NULLSTR, 1000);\r\n    cout << ss << endl;\r\n\r\n    return true;\r\n}\r\n\r\nbool testInvalidConfig() {\r\n    cout << \"in function testInvalidConfig\" << endl;\r\n    Properties props;\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n\r\n    NacosString ss;\r\n    try {\r\n        INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n        ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n        ConfigService *n = factory->CreateConfigService();\r\n        ResourceGuard <ConfigService> _serviceFactory(n);\r\n        ss = n->getConfig(\"k\", NULLSTR, 1000);\r\n    }\r\n    catch (NacosException &e) {\r\n        NacosString errmsgShouldBe = \"no server address specified and the endpoint is blank\";\r\n        if (errmsgShouldBe == e.what()) {\r\n            return true;\r\n        } else {\r\n            return false;\r\n        }\r\n    }\r\n    cout << ss << endl;\r\n\r\n    return false;\r\n}"
  },
  {
    "path": "test/testcase/testGetServiceNames.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <unistd.h>\n#include <list>\n#include \"src/naming/NamingProxy.h\"\n#include \"factory/NacosFactoryFactory.h\"\n#include \"naming/Instance.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/UtilAndComs.h\"\n#include \"src/http/HTTPCli.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"ResourceGuard.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testGetServiceNames() {\n    cout << \"in function testGetServiceNames\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService(namingSvc);\n\n    ListView<NacosString> res;\n    try {\n        res = namingSvc->getServiceList(1, 10);\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while getting service names, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    list<NacosString> nameList = res.getData();\n    for (list<NacosString>::const_iterator it = nameList.begin();\n        it != nameList.end(); it++) {\n        cout << \"serviceName:\" << *it << endl;\n    }\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testHttpRequest.cpp",
    "content": "#include \"src/http/HTTPCli.h\"\r\n#include \"src/log/Logger.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include <iostream>\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n#define DEFAULT_ENCODING \"UTF-8\"\r\n\r\nbool testNormalHttpRequest() {\r\n    cout << \"in function testNormalHttpRequest\" << endl;\r\n    NacosString path = \"http://127.0.0.1:8848/nacos/v1/ns/operator/servers\";\r\n    NacosString ENCODING = DEFAULT_ENCODING;\r\n    std::list <NacosString> headers;\r\n    std::list <NacosString> paramValues;\r\n    HTTPCli httpcli;\r\n    HttpResult callres;\r\n    try {\r\n        callres = httpcli.httpGet(path,\r\n                                  headers,\r\n                                  paramValues,\r\n                                  ENCODING,\r\n                                  1000);\r\n    }\r\n    catch (NetworkException &e) {\r\n        cout <<\r\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\r\n             \"Reason:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    cout << \"Http Request returned with code:\" << callres.code << endl;\r\n    cout << \"Headers:\" << endl;\r\n\r\n    for (std::map<NacosString, NacosString>::iterator it = callres.headers.begin();\r\n         it != callres.headers.end(); ++it) {\r\n        cout << it->first << \":\" << it->second << endl;\r\n    }\r\n\r\n    cout << \"Content:\" << callres.content << endl;\r\n    return true;\r\n}\r\n\r\nbool testNoServerRequest() {\r\n    cout << \"in function testNoServerRequest\" << endl;\r\n    NacosString path = \"http://127.0.0.1:9999/nacos/v1/ns/operator/servers\";\r\n    NacosString ENCODING = DEFAULT_ENCODING;\r\n    std::list <NacosString> headers;\r\n    std::list <NacosString> paramValues;\r\n    HTTPCli httpcli;\r\n    HttpResult callres;\r\n    try {\r\n        callres = httpcli.httpGet(path,\r\n                                  headers,\r\n                                  paramValues,\r\n                                  ENCODING,\r\n                                  1000);\r\n    }\r\n    catch (NetworkException &e) {\r\n        //should throw a exception\r\n        cout <<\r\n             \"Request failed with curl code:\" << e.errorcode() << endl <<\r\n             \"Reason:\" << e.what() << endl;\r\n        return true;\r\n    }\r\n\r\n    cout << \"Http Request returned with code:\" << callres.code << endl;\r\n    cout << \"Headers:\" << endl;\r\n\r\n    for (std::map<NacosString, NacosString>::iterator it = callres.headers.begin();\r\n         it != callres.headers.end(); ++it) {\r\n        cout << it->first << \":\" << it->second << endl;\r\n    }\r\n\r\n    cout << \"Content:\" << callres.content << endl;\r\n    return false;\r\n}"
  },
  {
    "path": "test/testcase/testIOUtils.cpp",
    "content": "#include <iostream>\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/config/IOUtils.h\"\r\n#include \"src/utils/DirUtils.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\n#define ENCODING \"UTF-8\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testReadWriteFile() {\r\n    cout << \"in function testReadWriteFile\" << endl;\r\n\r\n    NacosString cwd = DirUtils::getCwd();\r\n    NacosString tmpPath = cwd + \"/tmp\";\r\n    IOUtils::recursivelyCreate(tmpPath);\r\n    NacosString writeFile = tmpPath + \"/testfile\";\r\n    IOUtils::writeStringToFile(writeFile, \"nacos-cpp-cli-test\", ENCODING);\r\n\r\n    NacosString content = IOUtils::readStringFromFile(writeFile, ENCODING);\r\n    SHOULD_BE_TRUE(content == \"nacos-cpp-cli-test\",\r\n                   \"NacosString \\\"nacos-cpp-cli-test\\\" is written to file, should be the same when reading\");\r\n    return true;\r\n}\r\n\r\nbool testGetFileSize() {\r\n    cout << \"in function testGetFileSize\" << endl;\r\n\r\n    NacosString cwd = DirUtils::getCwd();\r\n    NacosString tmpPath = cwd + \"/tmp\";\r\n    IOUtils::recursivelyCreate(tmpPath);\r\n    NacosString writeFile = tmpPath + \"/testfile\";\r\n    IOUtils::writeStringToFile(writeFile, \"nacos-cpp-cli-test\", ENCODING);\r\n\r\n    size_t sz = IOUtils::getFileSize(writeFile);\r\n    SHOULD_BE_TRUE(sz == 18, \"NacosString \\\"nacos-cpp-cli-test\\\" is written to file, size should be 18\");\r\n    return true;\r\n}\r\n\r\nbool testFileExists() {\r\n    cout << \"in function testFileExists\" << endl;\r\n\r\n    NacosString cwd = DirUtils::getCwd();\r\n    NacosString tmpPath = cwd + \"/tmp\";\r\n    NacosString writeFile = tmpPath + \"/testfile\";\r\n    IOUtils::recursivelyRemove(tmpPath);\r\n\r\n    cout << \"Cwd:\" << cwd << endl;\r\n    SHOULD_BE_TRUE(IOUtils::checkNotExistOrNotFile(cwd), \"The source folder should be a folder, not a file\");\r\n    SHOULD_BE_FALSE(IOUtils::checkNotExistOrNotDir(cwd), \"The source folder should be a folder\");\r\n\r\n    IOUtils::recursivelyCreate(tmpPath);\r\n    IOUtils::writeStringToFile(writeFile, \"nacos-cpp-cli-test\", ENCODING);\r\n    SHOULD_BE_FALSE(IOUtils::checkNotExistOrNotFile(writeFile),\r\n                    \"Created a file named \\\"testfile\\\" with content \\\"nacos-cpp-cli-test\\\"\");\r\n    return true;\r\n}\r\n\r\n\r\nbool testCreateAndRemove() {\r\n    cout << \"in function testFileExists\" << endl;\r\n\r\n    NacosString cwd = DirUtils::getCwd();\r\n    NacosString tmpPath = cwd + \"/tmp/123/456/789/2312/afda/4__dsa/dd_\";\r\n    NacosString rmpath = cwd + \"/tmp/123\";\r\n    IOUtils::recursivelyCreate(tmpPath);\r\n    SHOULD_BE_FALSE(IOUtils::checkNotExistOrNotDir(tmpPath), \"We have created a dir, it should exist\");\r\n    IOUtils::recursivelyRemove(rmpath);\r\n    SHOULD_BE_TRUE(IOUtils::checkNotExistOrNotFile(cwd + \"/tmp\"), \"Removed everything except the tmp folder\");\r\n    NacosString easterEgg = cwd + \"/tmp/Liao/Sijia\";\r\n    IOUtils::recursivelyCreate(easterEgg);\r\n    return true;\r\n}\r\n\r\nbool testCleanDirectory() {\r\n    cout << \"in function testCleanDirectory\" << endl;\r\n\r\n    NacosString cwd = DirUtils::getCwd();\r\n    NacosString tmpPath = cwd + \"/tmp/testcleandir/456/789/2312/afda/4__dsa/dd_\";\r\n    NacosString cleanPath = cwd + \"/tmp/testcleandir\";\r\n    IOUtils::recursivelyCreate(tmpPath);\r\n    SHOULD_BE_FALSE(IOUtils::checkNotExistOrNotDir(tmpPath), \"We have created a dir, it should exist\");\r\n    IOUtils::cleanDirectory(cleanPath);\r\n    SHOULD_BE_TRUE(IOUtils::checkNotExistOrNotDir(tmpPath),\r\n                   \"Subdirectories of the dir is cleaned, it should not exist\");\r\n    SHOULD_BE_FALSE(IOUtils::checkNotExistOrNotDir(cleanPath), \"The dir is cleaned, but itself should exist\");\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testInstanceSelector.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <unistd.h>\n#include <list>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"naming/Instance.h\"\n#include \"naming/selectors/RandomByWeightSelector.h\"\n#include \"naming/selectors/HealthInstanceSelector.h\"\n#include \"naming/selectors/RandomSelector.h\"\n#include \"constant/ConfigConstant.h\"\n#include \"constant/UtilAndComs.h\"\n#include \"src/http/HTTPCli.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"ResourceGuard.h\"\n\nusing namespace std;\nusing namespace nacos;\nusing namespace nacos::naming::selectors;\n\nbool testInstanceSelectors() {\n    cout << \"in function testInstanceSelectors\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL] = \"3000\";\n\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService(namingSvc);\n\n    list<Instance> res;\n    HealthInstanceSelector healthInstanceSelector;\n    RandomSelector randomSelector;\n\n    Instance instance;\n    instance.clusterName = \"DefaultCluster\";\n    instance.ip = \"127.0.0.1\";\n    instance.port = 2333;\n    instance.instanceId = \"1\";\n    instance.ephemeral = true;\n\n    try {\n        for (int i = 0; i < 10; i++) {\n            NacosString serviceName = \"TestNamingService0\";\n            instance.port = 2000 + i;\n            namingSvc->registerInstance(serviceName, instance);\n        }\n        res = namingSvc->getInstanceWithPredicate(\"TestNamingService0\", &randomSelector);\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while getting service names, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    cout << \"Selected instance(s):\" << endl;\n    for (list<Instance>::const_iterator it = res.begin();\n         it != res.end(); it++) {\n        cout << \"service:\" << it->toString() << endl;\n    }\n\n    return true;\n}\n\nbool testRandomByWeightSelector()\n{\n\n    cout << \"in function testRandomByWeightSelector\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    configProps[PropertyKeyConst::SUBSCRIPTION_POLL_INTERVAL] = \"3000\";\n\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *namingSvc = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService(namingSvc);\n\n    Instance instance;\n    instance.clusterName = \"DefaultCluster\";\n    instance.ip = \"127.0.0.1\";\n    instance.port = 2333;\n    instance.instanceId = \"1\";\n    instance.ephemeral = true;\n    RandomByWeightSelector randomByWeightSelector;\n\n    try {\n        for (int i = 0; i < 10; i++) {\n            NacosString serviceName = \"TestNamingService0\";\n            instance.port = 2000 + i;\n            instance.weight = i + 1;\n            namingSvc->registerInstance(serviceName, instance);\n        }\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    cout << \"start to select instance with selectors \" << endl;\n\n    for (int i = 0; i < 20; i++)\n    {\n        list<Instance> res = namingSvc->getInstanceWithPredicate(\"TestNamingService0\", &randomByWeightSelector);\n\n        for (list<Instance>::const_iterator it = res.begin();\n             it != res.end(); it++) {\n            cout << \"service:\" << it->toString() << endl;\n        }\n    }\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testJson2BizObjects.cpp",
    "content": "#include <iostream>\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/json/rapidjson/document.h\"\r\n#include \"src/json/rapidjson/writer.h\"\r\n#include \"src/json/rapidjson/stringbuffer.h\"\r\n#include \"src/naming/beat/BeatInfo.h\"\r\n#include \"src/json/JSON.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testString2ServiceInfo() {\r\n    cout << \"in function testString2ServiceInfo\" << endl;\r\n    const char *json =\r\n            \"{\"\r\n            \"\t\\\"dom\\\": \\\"nacos.test.1\\\",\"\r\n            \"\t\\\"cacheMillis\\\": 1000,\"\r\n            \"\t\\\"useSpecifiedURL\\\": false,\"\r\n            \"\t\\\"hosts\\\": [{\"\r\n            \"\t\t\\\"valid\\\": true,\"\r\n            \"\t\t\\\"marked\\\": false,\"\r\n            \"\t\t\\\"instanceId\\\": \\\"10.10.10.10-8888-DEFAULT-nacos.test.1\\\",\"\r\n            \"\t\t\\\"port\\\": 8888,\"\r\n            \"\t\t\\\"ip\\\": \\\"10.10.10.10\\\",\"\r\n            \"\t\t\\\"weight\\\": 1.0,\"\r\n            \"\t    \\\"healthy\\\": true,\"\r\n            \"\t    \\\"enabled\\\": true,\"\r\n            \"\t\t\\\"metadata\\\": {}\"\r\n            \"\t}],\"\r\n            \"\t\\\"checksum\\\": \\\"3bbcf6dd1175203a8afdade0e77a27cd1528787794594\\\",\"\r\n            \"\t\\\"lastRefTime\\\": 1528787794594,\"\r\n            \"\t\\\"env\\\": \\\"\\\",\"\r\n            \"\t\\\"clusters\\\": \\\"\\\",\"\r\n            \"\t\\\"name\\\": \\\"test\\\"\"\r\n            \"}\";\r\n\r\n    cout << \"Deserializing the following string into an object:\" << endl << json << endl;\r\n    ServiceInfo si = JSON::JsonStr2ServiceInfo(json);\r\n\r\n    SHOULD_BE_TRUE(si.getHosts().size() == 1, \"There is 1 host in the json object\");\r\n    SHOULD_BE_TRUE(si.getClusters() == \"\", \"obj.cluster == \\\"\\\"\");\r\n    Instance i = si.getHosts().front();\r\n    SHOULD_BE_TRUE(i.instanceId == \"10.10.10.10-8888-DEFAULT-nacos.test.1\",\r\n                   \"The first instance's ID is 10.10.10.10-8888-DEFAULT-nacos.test.1\");\r\n    return true;\r\n}\r\n\r\nbool testMalformedJson2ServiceInfo() {\r\n    cout << \"in function testMalformedJson2ServiceInfo\" << endl;\r\n    const char *json =\r\n            \"{\"\r\n            \"\t\\\"dom\\\": \\\"nacos.test.1\\\",\"\r\n            \"\t\\\"cacheMillis\\\": 1000,\"\r\n            \"\t\\\"useSpecifiedURL\\\": false,\"\r\n            \"\t\\\"hosts\\\": [{\"\r\n            \"\t\t\\\"valid\\\": true,\"\r\n            \"\t\t\\\"marked\\\": false,\"\r\n            \"\t\t\\\"instanceId\\\": \\\"10.10.10.10-8888-DEFAULT-nacos.test.1\\\",\"\r\n            \"\t\t\\\"port\\\": 8888,\"\r\n            \"\t\t\\\"ip\\\": \\\"10.10.10.10\\\",\"\r\n            \"\t\t\\\"weight\\\": 1.0,\"\r\n            \"\t    \\\"healthy\\\": true,\"\r\n            \"\t    \\\"enabled\\\": true,\"\r\n            \"\t\t\\\"metadata\\\": {}\"\r\n            \"\t}],\"\r\n            \"\t\\\"checksum\\\": \\\"3bbcf6dd1175203a8afdade0e77a27cd1528787794594\\\",\"\r\n            \"\t\\\"lastRefTime\\\": 152878779459499999999999999999999999999999999999999,\"\r\n            \"\t\\\"env\\\": \\\"\\\",\"\r\n            \"\t\\\"clusters\\\": \\\"\\\",\"\r\n            \"\t\\\"name\\\": \\\"test\\\"\"\r\n            \"}\";\r\n\r\n    cout << \"Deserializing the following string into an object:\" << endl << json << endl;\r\n    ServiceInfo si;\r\n    bool invalidJsonFormatException = false;\r\n    try {\r\n        si = JSON::JsonStr2ServiceInfo(json);\r\n    }\r\n    catch (NacosException &e) {\r\n        invalidJsonFormatException = true;\r\n        cout << \"Caught exception:\" << e.what() << endl;\r\n        SHOULD_BE_TRUE(e.errorcode() == NacosException::INVALID_JSON_FORMAT,\r\n                       \"Exception should be NacosException::INVALID_JSON_FORMAT\");\r\n    }\r\n    SHOULD_BE_TRUE(invalidJsonFormatException, \"This json string can't be parsed\");\r\n    return true;\r\n}\r\n\r\nbool testMalformedDouble2ServiceInfo() {\r\n    cout << \"in function testMalformedJson2ServiceInfo\" << endl;\r\n    const char *json =\r\n            \"{\"\r\n            \"\t\\\"dom\\\": \\\"nacos.test.1\\\",\"\r\n            \"\t\\\"cacheMillis\\\": 1000,\"\r\n            \"\t\\\"useSpecifiedURL\\\": false,\"\r\n            \"\t\\\"hosts\\\": [{\"\r\n            \"\t\t\\\"valid\\\": true,\"\r\n            \"\t\t\\\"marked\\\": false,\"\r\n            \"\t\t\\\"instanceId\\\": \\\"10.10.10.10-8888-DEFAULT-nacos.test.1\\\",\"\r\n            \"\t\t\\\"port\\\": 8888,\"\r\n            \"\t\t\\\"ip\\\": \\\"10.10.10.10\\\",\"\r\n            \"\t\t\\\"weight\\\": 1999999999999999999999999999999999999999..0,\"\r\n            \"\t    \\\"healthy\\\": true,\"\r\n            \"\t    \\\"enabled\\\": true,\"\r\n            \"\t\t\\\"metadata\\\": {}\"\r\n            \"\t}],\"\r\n            \"\t\\\"checksum\\\": \\\"3bbcf6dd1175203a8afdade0e77a27cd1528787794594\\\",\"\r\n            \"\t\\\"lastRefTime\\\": 1528787794594,\"\r\n            \"\t\\\"env\\\": \\\"\\\",\"\r\n            \"\t\\\"clusters\\\": \\\"\\\",\"\r\n            \"\t\\\"name\\\": \\\"test\\\"\"\r\n            \"}\";\r\n\r\n    cout << \"Deserializing the following string into an object:\" << endl << json << endl;\r\n    ServiceInfo si;\r\n    bool invalidJsonFormatException = false;\r\n    try {\r\n        si = JSON::JsonStr2ServiceInfo(json);\r\n    }\r\n    catch (NacosException &e) {\r\n        if (e.errorcode() == NacosException::INVALID_JSON_FORMAT) {\r\n            invalidJsonFormatException = true;\r\n        }\r\n        cout << \"Caught exception:\" << e.what() << endl;\r\n        SHOULD_BE_TRUE(e.errorcode() == NacosException::INVALID_JSON_FORMAT,\r\n                       \"Exception should be NacosException::INVALID_JSON_FORMAT\");\r\n    }\r\n    SHOULD_BE_TRUE(invalidJsonFormatException, \"This json string can't be parsed\");\r\n    return true;\r\n}\r\n\r\nbool testLackcacheMillisServiceInfo() {\r\n    cout << \"in function testMalformedJson2ServiceInfo\" << endl;\r\n    const char *json =\r\n            \"{\"\r\n            \"\t\\\"dom\\\": \\\"nacos.test.1\\\",\"\r\n            /*\"\t\\\"cacheMillis\\\": 1000,\"*///<- no cacheMillis\r\n            \"\t\\\"useSpecifiedURL\\\": false,\"\r\n            \"\t\\\"hosts\\\": [{\"\r\n            \"\t\t\\\"valid\\\": true,\"\r\n            \"\t\t\\\"marked\\\": false,\"\r\n            \"\t\t\\\"instanceId\\\": \\\"10.10.10.10-8888-DEFAULT-nacos.test.1\\\",\"\r\n            \"\t\t\\\"port\\\": 8888,\"\r\n            \"\t\t\\\"ip\\\": \\\"10.10.10.10\\\",\"\r\n            \"\t\t\\\"weight\\\": 1.0,\"\r\n            \"\t    \\\"healthy\\\": true,\"\r\n            \"\t    \\\"enabled\\\": true,\"\r\n            \"\t\t\\\"metadata\\\": {}\"\r\n            \"\t}],\"\r\n            \"\t\\\"checksum\\\": \\\"3bbcf6dd1175203a8afdade0e77a27cd1528787794594\\\",\"\r\n            \"\t\\\"lastRefTime\\\": 1528787794594,\"\r\n            \"\t\\\"env\\\": \\\"\\\",\"\r\n            \"\t\\\"clusters\\\": \\\"\\\",\"\r\n            \"\t\\\"name\\\": \\\"test\\\"\"\r\n            \"}\";\r\n\r\n    cout << \"Deserializing the following string into an object:\" << endl << json << endl;\r\n    ServiceInfo si;\r\n    bool invalidJsonFormatException = false;\r\n    try {\r\n        si = JSON::JsonStr2ServiceInfo(json);\r\n    }\r\n    catch (NacosException &e) {\r\n        if (e.errorcode() == NacosException::INVALID_JSON_FORMAT) {\r\n            invalidJsonFormatException = true;\r\n        }\r\n        cout << \"Caught exception:\" << e.what() << endl;\r\n        SHOULD_BE_TRUE(e.errorcode() == NacosException::LACK_JSON_FIELD,\r\n                       \"Exception should be NacosException::LACK_JSON_FIELD\");\r\n    }\r\n    SHOULD_BE_FALSE(invalidJsonFormatException, \"This JSON is parsable, but cacheMillis is missing\");\r\n    return true;\r\n}\r\n\r\n"
  },
  {
    "path": "test/testcase/testListenWorker.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include <stdio.h>\r\n#include <unistd.h>\r\n#include \"src/log/Logger.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"listen/Listener.h\"\r\n#include \"src/http/HttpDelegate.h\"\r\n#include \"factory/NacosFactoryFactory.h\"\r\n#include \"ResourceGuard.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool key_change_called = false;\r\n\r\nclass KeyChangeListener : public Listener {\r\nprivate:\r\n    NacosString key;\r\npublic:\r\n    void setKey(const NacosString &_key) { key = _key; };\r\n\r\n    NacosString getKey() const { return key; };\r\n\r\n    void receiveConfigInfo(const NacosString &configInfo) {\r\n        key_change_called = true;\r\n        cout << \"in receiveConfigInfo: \" << key << \" changed to \" << configInfo << endl;\r\n    }\r\n};\r\n\r\nbool testAddListener() {\r\n    cout << \"in function testAddListener\" << endl;\r\n    Properties props;\r\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    KeyChangeListener *thelistener = new KeyChangeListener();\r\n    thelistener->setKey(\"k\");\r\n    bool bSucc;\r\n    try {\r\n        INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n        ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n        ConfigService *n = factory->CreateConfigService();\r\n        ResourceGuard <ConfigService> _serviceFactory(n);\r\n        n->removeConfig(\"k4\", NULLSTR);\r\n        n->removeConfig(\"k2\", NULLSTR);//Known issue: this key will be monitored in next cycle(LONG_PULLING_TIME)\r\n        n->removeConfig(\"k\", NULLSTR);//so will this\r\n        sleep(1);\r\n        n->addListener(\"k4\", NULLSTR, thelistener);\r\n        n->addListener(\"k2\", NULLSTR, thelistener);\r\n        n->addListener(\"k\", NULLSTR, thelistener);\r\n        sleep(1);\r\n        cout << \"publish k\" << endl;\r\n        bSucc = n->publishConfig(\"k4\", NULLSTR, \"hahaha\");\r\n    }\r\n    catch (NacosException &e) {\r\n        cout <<\r\n             \"Failed to add listener\" << endl <<\r\n             \"Reason:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    SHOULD_BE_TRUE(key_change_called, \"Notification function should be called\");\r\n    SHOULD_BE_TRUE(bSucc, \"Publish should succeed\");\r\n    cout << \"test successful\" << endl;\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testListeningKeys.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"listen/Listener.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyListener : public Listener {\nprivate:\n    int num;\npublic:\n    MyListener(int num) {\n        this->num = num;\n    }\n\n    void receiveConfigInfo(const NacosString &configInfo) {\n        cout << \"===================================\" << endl;\n        cout << \"Watcher\" << num << endl;\n        cout << \"Watched Key UPDATED:\" << configInfo << endl;\n        cout << \"===================================\" << endl;\n    }\n};\n\nbool testListeningKeys() {\n    cout << \"in function testListeningKeys\" << endl;\n    Properties props;\n    ADD_AUTH_INFO(props);\n    ADD_SPAS_INFO(props);\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n\n    MyListener *theListener = new MyListener(1);\n    MyListener *theListener2 = new MyListener(2);\n    MyListener *theListener3 = new MyListener(3);\n    n->addListener(\"dqid\", NULLSTR, theListener);\n    n->addListener(\"dqid\", NULLSTR, theListener2);\n    n->addListener(\"dqid\", NULLSTR, theListener3);\n    n->addListener(\"dqid1\", NULLSTR, theListener3);\n    n->addListener(\"dqid2\", NULLSTR, theListener3);\n    n->addListener(\"dqid3\", NULLSTR, theListener3);\n\n    for (int i = 10; i < 60; i++) {\n        NacosString strKey = \"dqid\" + NacosStringOps::valueOf(i);\n        n->addListener(strKey, NULLSTR, theListener3);\n    }\n\n    cout << \"Change key and hold for 15 secs\" << endl;\n    n->publishConfig(\"dqid\", NULLSTR, \"Hello\");\n    n->publishConfig(\"dqid\", NULLSTR, \"World\");\n    sleep(15);\n    cout << \"remove listener\" << endl;\n    n->removeListener(\"dqid\", NULLSTR, theListener);\n\n    cout << \"Hold for 15 secs\" << endl;\n    n->publishConfig(\"dqid3\", NULLSTR, \"Hello-3\");\n    n->publishConfig(\"dqid3\", NULLSTR, \"World-3\");\n    n->publishConfig(\"dqid1\", NULLSTR, \"World-3\");\n    n->publishConfig(\"dqid2\", NULLSTR, \"World-3\");\n    n->publishConfig(\"dqid3\", NULLSTR, \"World-3\");\n    n->publishConfig(\"dqid1\", NULLSTR, \"World-3\");\n    n->publishConfig(\"dqid2\", NULLSTR, \"World-3\");\n    n->publishConfig(\"dqid3\", NULLSTR, \"World-3\");\n    sleep(15);\n    cout << \"remove listener2\" << endl;\n    n->publishConfig(\"dqid\", NULLSTR, \"Data change before remove\");\n    n->removeListener(\"dqid\", NULLSTR, theListener2);\n    n->removeListener(\"dqid\", NULLSTR, theListener3);\n    n->publishConfig(\"dqid\", NULLSTR, \"Data change after remove\");\n    cout << \"test successful\" << endl;\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testListeningKeysWithHttpPrefix.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"listen/Listener.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyListenerHttpPrefix : public Listener {\nprivate:\n    int num;\npublic:\n    MyListenerHttpPrefix(int num) {\n        this->num = num;\n    }\n\n    void receiveConfigInfo(const NacosString &configInfo) {\n        cout << \"===================================\" << endl;\n        cout << \"Watcher\" << num << endl;\n        cout << \"Watched Key UPDATED:\" << configInfo << endl;\n        cout << \"===================================\" << endl;\n    }\n};\n\nbool testListeningKeysWithHttpPrefix() {\n    cout << \"in function testListeningKeysWithHttpPrefix\" << endl;\n    Properties props;\n    ADD_AUTH_INFO(props);\n    ADD_SPAS_INFO(props);\n    props[PropertyKeyConst::SERVER_ADDR] = \"HttP://127.0.0.1:8848,HtTP://localhost\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n\n    MyListenerHttpPrefix *theListener = new MyListenerHttpPrefix(1);\n    MyListenerHttpPrefix *theListener2 = new MyListenerHttpPrefix(2);\n    MyListenerHttpPrefix *theListener3 = new MyListenerHttpPrefix(3);\n    n->addListener(\"dqid\", NULLSTR, theListener);\n    n->addListener(\"dqid\", NULLSTR, theListener2);\n    n->addListener(\"dqid\", NULLSTR, theListener3);\n    n->addListener(\"dqid1\", NULLSTR, theListener3);\n    n->addListener(\"dqid2\", NULLSTR, theListener3);\n    n->addListener(\"dqid3\", NULLSTR, theListener3);\n\n    for (int i = 10; i < 60; i++) {\n        NacosString strKey = \"dqid\" + NacosStringOps::valueOf(i);\n        n->addListener(strKey, NULLSTR, theListener3);\n    }\n\n    cout << \"Hold for 20 secs\" << endl;\n    sleep(20);\n    cout << \"remove listener\" << endl;\n    n->removeListener(\"dqid\", NULLSTR, theListener);\n\n    cout << \"Hold for 20 secs\" << endl;\n    sleep(20);\n    cout << \"remove listener2\" << endl;\n    n->removeListener(\"dqid\", NULLSTR, theListener2);\n    n->removeListener(\"dqid\", NULLSTR, theListener3);\n    cout << \"test successful\" << endl;\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testMAC.cpp",
    "content": "#include <iostream>\n#include <string.h>\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/crypto/MACProvider.h\"\n\nusing namespace std;\nusing namespace nacos;\n\ntypedef struct _HMACSHA1TestCase {\n    const char *key;\n    size_t key_len;\n    const char *data;\n    size_t data_len;\n    const char *digest;\n} HMACSHA1TestCase;\n\nHMACSHA1TestCase HMACSHA1TestCases[] = {\n    {\"\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\\x0b\", 20, \"Hi There\", 8, \"\\xb6\\x17\\x31\\x86\\x55\\x05\\x72\\x64\\xe2\\x8b\\xc0\\xb6\\xfb\\x37\\x8c\\x8e\\xf1\\x46\\xbe\\x00\"},\n    {\"Jefe\", 4, \"what do ya want for nothing?\", 28, \"\\xef\\xfc\\xdf\\x6a\\xe5\\xeb\\x2f\\xa2\\xd2\\x74\\x16\\xd5\\xf1\\x84\\xdf\\x9c\\x25\\x9a\\x7c\\x79\"},\n    {\"\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\", 20, \"\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\\xdd\", 50, \"\\x12\\x5d\\x73\\x42\\xb9\\xac\\x11\\xcd\\x91\\xa3\\x9a\\xf4\\x8a\\xa1\\x7b\\x4f\\x63\\xf1\\x75\\xd3\"},\n    {\"\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\", 25, \"\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\\xcd\", 50, \"\\x4c\\x90\\x07\\xf4\\x02\\x62\\x50\\xc6\\xbc\\x84\\x14\\xf9\\xbf\\x50\\xc8\\x6c\\x2d\\x72\\x35\\xda\"},\n    {\"\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\\x0c\", 20, \"Test With Truncation\", 20, \"\\x4c\\x1a\\x03\\x42\\x4b\\x55\\xe0\\x7f\\xe7\\xf2\\x7b\\xe1\\xd5\\x8b\\xb9\\x32\\x4a\\x9a\\x5a\\x04\"},\n    {\"\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\", 80, \"Test Using Larger Than Block-Size Key - Hash Key First\", 54, \"\\xaa\\x4a\\xe5\\xe1\\x52\\x72\\xd0\\x0e\\x95\\x70\\x56\\x37\\xce\\x8a\\x3b\\x55\\xed\\x40\\x21\\x12\"},\n    {\"\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\\xaa\", 80, \"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data\", 73, \"\\xe8\\xe9\\x9d\\x0f\\x45\\x23\\x7d\\x78\\x6d\\x6b\\xba\\xa7\\x96\\x5c\\x78\\x08\\xbb\\xff\\x1a\\x91\"},\n};\n\nbool testHMACSHA1() {\n    //Actually, I've no idea why Alibaba is still using this old-school MAC algorithm :(\n    cout << \"In function testHMACSHA1()\" << endl;\n    cout << \"Getting MAC algorithm\" << endl;\n    cout << \"Test case acquired at https://datatracker.ietf.org/doc/html/rfc2202\" << endl;\n\n    IMAC *digester = MACProvider::getMAC(MACProvider::HMAC_SHA1);\n    SHOULD_BE_TRUE(digester != NULL, \"Should be able to get a IMAC* from MACProvider\");\n\n    for (size_t i = 0; i < sizeof(HMACSHA1TestCases) / sizeof(HMACSHA1TestCase); i++) {\n        const void *k = (const void*)HMACSHA1TestCases[i].key;\n        size_t kl = HMACSHA1TestCases[i].key_len;\n\n        const void *data = (const void*)HMACSHA1TestCases[i].data;\n        size_t dl = HMACSHA1TestCases[i].data_len;\n\n        char out[256] = {0};\n        size_t out_l = sizeof(out);\n\n        digester->getMac(k, kl, data, dl, out, &out_l);\n        SHOULD_BE_TRUE(out_l == 20, \"Digested data should be 20-bytes long\");\n\n        SHOULD_BE_TRUE(memcmp(out, HMACSHA1TestCases[i].digest, 20)  == 0, \"Checking digested data with test vector\");\n\n        cout << \"Test case \" << i + 1 << \": out_l=\" << out_l << \" passed.\" <<endl;\n    }\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testMD5.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include \"src/crypto/md5/md5.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testMD5() {\r\n    cout << \"in function testMD5\" << endl;\r\n    MD5 md5;\r\n\r\n    cout << \"Checking md5 for \\\"a\\\"\" << endl;\r\n    md5.reset();\r\n    md5.update(\"a\");\r\n    cout << \"md5:\" << md5.toString() << endl;\r\n    SHOULD_BE_TRUE(md5.toString() == \"0cc175b9c0f1b6a831c399e269772661\",\r\n                   \"NacosString \\\"a\\\" md5 should be 0cc175b9c0f1b6a831c399e269772661\");\r\n    cout << \"Checking md5 for \\\"aaaaaaa\\\"\" << endl;\r\n    md5.reset();\r\n    md5.update(\"aaaaaaa\");\r\n    cout << \"md5:\" << md5.toString() << endl;\r\n    SHOULD_BE_TRUE(md5.toString() == \"5d793fc5b00a2348c3fb9ab59e5ca98a\",\r\n                   \"NacosString \\\"aaaaaaa\\\" md5 should be 5d793fc5b00a2348c3fb9ab59e5ca98a\");\r\n    cout << \"Checking md5 for \\\"2652451346435432\\\"\" << endl;\r\n    md5.reset();\r\n    md5.update(\"2652451346435432\");\r\n    cout << \"md5:\" << md5.toString() << endl;\r\n    SHOULD_BE_TRUE(md5.toString() == \"69a8b79497dc611dcf9326a0b232ae55\",\r\n                   \"NacosString \\\"2652451346435432\\\" md5 should be 69a8b79497dc611dcf9326a0b232ae55\");\r\n    return true;\r\n}\r\n"
  },
  {
    "path": "test/testcase/testMaintainInstances.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <unistd.h>\n#include <list>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"naming/NamingMaintainService.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"ResourceGuard.h\"\n#include \"constant/ConfigConstant.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testMaintainUpdateInstance() {\n    cout << \"in function testMaintainUpdateInstance\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingMaintainService *maintainService = factory->CreateNamingMaintainService();\n    ResourceGuard <NamingMaintainService> _guardService(maintainService);\n    NamingService *namingService = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService2(namingService);\n\n    ListView<NacosString> res;\n    try {\n        Instance instance;\n        instance.serviceName = \"MaintainTestUpdateInstance\";\n        instance.ip = \"127.0.0.1\";\n        instance.port = 2333;\n        instance.ephemeral = false;\n        try {\n            maintainService->deleteService(\"MaintainTestUpdateInstance\", ConfigConstant::DEFAULT_GROUP);\n        } catch (exception &ignore) { /*We may come across service not exist exception, just ignore*/ }\n        namingService->registerInstance(\"MaintainTestUpdateInstance\", instance);\n        map<NacosString, NacosString> metadata;\n        metadata.insert(make_pair(\"hello\", \"world\"));\n        instance.metadata = metadata;\n        bool res = maintainService->updateInstance(\"MaintainTestUpdateInstance\", NULLSTR, instance);\n        SHOULD_BE_TRUE(res, \"updateInstance should succeed\");\n\n        list<Instance> instanceList = namingService->getInstanceWithPredicate(\"MaintainTestUpdateInstance\", NULL);\n        SHOULD_BE_TRUE(instanceList.size() == 1, \"there should be one and only one instance of MaintainTestUpdateInstance\");\n        map<NacosString, NacosString> &metadataGet = instanceList.begin()->metadata;\n        SHOULD_BE_TRUE(metadataGet.count(\"hello\") == 1, \"metadata should contain hello\");\n        SHOULD_BE_TRUE(metadataGet[\"hello\"].compare(\"world\") == 0, \"metadata should be {hello: world}\");\n        try {\n            //restore to the initial status\n            maintainService->deleteService(\"MaintainTestUpdateInstance\", ConfigConstant::DEFAULT_GROUP);\n        } catch (exception &ignore) { /*We may come across service not exist exception, just ignore*/ }\n        return true;\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while testing, raison:\" << e.what() << endl;\n        return false;\n    }\n}\n"
  },
  {
    "path": "test/testcase/testMaintainServices.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <unistd.h>\n#include <list>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"naming/NamingMaintainService.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n#include \"NacosString.h\"\n#include \"Properties.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"ResourceGuard.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testMaintainGetService() {\n    cout << \"in function testMaintainGetService\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingMaintainService *maintainService = factory->CreateNamingMaintainService();\n    ResourceGuard <NamingMaintainService> _guardService(maintainService);\n    NamingService *namingService = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService2(namingService);\n\n    ListView<NacosString> res;\n    try {\n        namingService->registerInstance(\"MaintainTestService\", \"127.0.0.1\", 2333);\n        ServiceInfo2 res = maintainService->queryService(\"MaintainTestService\", NULLSTR);\n        cout << \"service name got from server:\" << res.getName() << endl;\n        SHOULD_BE_TRUE(res.getName().compare(\"MaintainTestService\") == 0, \"Service name should be MaintainTestService\");\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while getting service, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool testMaintainUpdateService() {\n    cout << \"in function testMaintainUpdateService\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingMaintainService *maintainService = factory->CreateNamingMaintainService();\n    ResourceGuard <NamingMaintainService> _guardService(maintainService);\n    NamingService *namingService = factory->CreateNamingService();\n    ResourceGuard <NamingService> _guardService2(namingService);\n\n    ListView<NacosString> res;\n    try {\n        namingService->registerInstance(\"MaintainTestUpdateService\", \"127.0.0.1\", 2333);\n        ServiceInfo2 serviceInfo2;\n        serviceInfo2.setName(\"MaintainTestUpdateService\");\n        serviceInfo2.setProtectThreshold((double)2);\n        bool updateRes = maintainService->updateService(serviceInfo2, NULL);\n        cout << \"update protect threshold:\" << NacosStringOps::valueOf(updateRes) << endl;\n        SHOULD_BE_TRUE(updateRes, \"update of protect threshold should be successful\");\n\n        ServiceInfo2 serviceInfoQuery = maintainService->queryService(\"MaintainTestService\", NULLSTR);\n        SHOULD_BE_TRUE(serviceInfoQuery.getProtectThreshold() - 2.0 < 1e-9, \"protect threshold should be 2.0D\");\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while updating service, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    return true;\n}\n\n//actually this will test delete as well\nbool testMaintainCreateService() {\n    cout << \"in function testMaintainCreateService\" << endl;\n    Properties configProps;\n    ADD_AUTH_INFO(configProps);\n    ADD_SPAS_INFO(configProps);\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingMaintainService *maintainService = factory->CreateNamingMaintainService();\n    ResourceGuard <NamingMaintainService> _guardService(maintainService);\n\n    ListView<NacosString> res;\n    try {\n        ServiceInfo2 serviceInfo2;\n        serviceInfo2.setName(\"MaintainTestCreateService\");\n        serviceInfo2.setProtectThreshold((double)2);\n        map<NacosString, NacosString> metadata;\n        metadata.insert(make_pair(\"hello\", \"world\"));\n        metadata.insert(make_pair(\"girlfriend\", \"Liao, Sijia\"));\n        serviceInfo2.setMetadata(metadata);\n\n        try {\n            maintainService->deleteService(\"MaintainTestCreateService\", NULLSTR);\n        } catch (exception &ignore) {\n            log_debug(\"designated service does not exist\\n\");\n        }\n\n        bool createResult = maintainService->createService(serviceInfo2, NULL);\n        SHOULD_BE_TRUE(createResult, \"MaintainTestCreateService should be created\");\n\n        ServiceInfo2 serviceInfoQuery = maintainService->queryService(\"MaintainTestCreateService\", NULLSTR);\n        SHOULD_BE_TRUE(serviceInfoQuery.getProtectThreshold() - 2.0 < 1e-9, \"protect threshold should be 2.0D\");\n        SHOULD_BE_TRUE(serviceInfoQuery.getName().compare(\"MaintainTestCreateService\") == 0, \"name should be MaintainTestCreateService\");\n\n        map<NacosString, NacosString> returnedMetadata = serviceInfoQuery.getMetadata();\n        SHOULD_BE_TRUE(returnedMetadata.count(\"hello\") == 1, \"metadata should contain hello\");\n        SHOULD_BE_TRUE(returnedMetadata.count(\"girlfriend\") == 1, \"metadata should contain girlfriend\");\n        NacosString hello = returnedMetadata[\"hello\"];\n        SHOULD_BE_TRUE(hello.compare(\"world\") == 0 , \"hello should be world\");\n        NacosString girlfriend = returnedMetadata[\"girlfriend\"];\n        SHOULD_BE_TRUE(girlfriend.compare(\"Liao, Sijia\") == 0, \"girlfriend should be correct\");\n\n        bool deleteFunctionality = maintainService->deleteService(\"MaintainTestCreateService\", NULLSTR);\n        SHOULD_BE_TRUE(deleteFunctionality, \"delete should be successful\");\n\n    }\n    catch (NacosException &e) {\n        cout << \"encounter exception while updating service, raison:\" << e.what() << endl;\n        return false;\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "test/testcase/testNamingService.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include <unistd.h>\r\n#include \"src/naming/NamingProxy.h\"\r\n#include \"src/naming/NacosNamingService.h\"\r\n#include \"factory/NacosFactoryFactory.h\"\r\n#include \"ResourceGuard.h\"\r\n#include \"naming/Instance.h\"\r\n#include \"constant/ConfigConstant.h\"\r\n#include \"constant/UtilAndComs.h\"\r\n#include \"src/http/HTTPCli.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/log/Logger.h\"\r\n#include \"NacosString.h\"\r\n#include \"Properties.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n#define NR_SERVICE_INSTS 3\r\n#define NR_SERVICES 3\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testNamingProxySmokeTest() {\r\n    cout << \"in function testNamingProxySmokeTest\" << endl;\r\n    NacosString servers = \"127.0.0.1:8848\";\r\n    Properties props;\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    props[PropertyKeyConst::SERVER_ADDR] = servers;\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    NamingService *n = factory->CreateNamingService();\r\n    ResourceGuard <NamingService> _serviceFactory(n);\r\n    NacosNamingService *nn = (NacosNamingService *) n;\r\n    NamingProxy *namingProxy = nn->getServerProxy();\r\n    Instance theinstance;\r\n    theinstance.instanceId = \"TestInstance\";\r\n    theinstance.ip = \"127.0.0.1\";\r\n    theinstance.port = 3333;\r\n    theinstance.clusterName = \"TestCluster\";\r\n\r\n    //Create a clean environment\r\n    try {\r\n        for (int i = 0; i < 10; i++) {\r\n            NacosString serviceName = \"TestServiceName\" + NacosStringOps::valueOf(i);\r\n            theinstance.serviceName = serviceName;\r\n            namingProxy->deregisterService(serviceName, theinstance);\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"Exception caught during deregistering service, raison:\" << e.what() << endl;\r\n\r\n        return false;\r\n    }\r\n\r\n    //Register 100 services\r\n    try {\r\n        for (int i = 0; i < 10; i++) {\r\n            NacosString serviceName = \"TestServiceName\" + NacosStringOps::valueOf(i);\r\n            theinstance.serviceName = serviceName;\r\n            namingProxy->registerService(serviceName, ConfigConstant::DEFAULT_GROUP, theinstance);\r\n            sleep(1);\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"Exception caught during registering service, raison:\" << e.what() << endl;\r\n\r\n        return false;\r\n    }\r\n\r\n    //check whether the data are correct\r\n    for (int i = 0; i < 10; i++) {\r\n        NacosString serviceName = \"TestServiceName\" + NacosStringOps::valueOf(i);\r\n        NacosString serverlist = namingProxy->queryList(serviceName, ConfigConstant::DEFAULT_GROUP, \"TestCluster\", 0, false);\r\n        cout << serverlist << endl;\r\n        if (serverlist.find(\"\\\"serviceName\\\":\\\"\" + serviceName + \"\\\"\") == string::npos &&\r\n            //nacos 2.x compatibility\r\n            serverlist.find(\"\\\"serviceName\\\":\\\"DEFAULT_GROUP@@\" + serviceName + \"\\\"\") == string::npos) {\r\n            cout << \"Failed to get data for:\" << serviceName << endl;\r\n            return false;\r\n        }\r\n        cout << \"Servers from nacos:\" + serverlist << endl;\r\n    }\r\n\r\n    //Clear-ups\r\n    try {\r\n        for (int i = 0; i < 10; i++) {\r\n            NacosString serviceName = \"TestServiceName\" + NacosStringOps::valueOf(i);\r\n            theinstance.serviceName = serviceName;\r\n            namingProxy->deregisterService(serviceName, theinstance);\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"Exception caught during cleaning the test environment, raison:\" << e.what() << endl;\r\n\r\n        return false;\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\nbool testNamingProxyServerHealthy() {\r\n    cout << \"in function testNamingProxyServerHealthy\" << endl;\r\n    NacosString servers = \"127.0.0.1:8848\";\r\n    Properties props;\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    props[PropertyKeyConst::SERVER_ADDR] = servers;\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    NamingService *n = factory->CreateNamingService();\r\n    ResourceGuard <NamingService> _serviceFactory(n);\r\n    NacosNamingService *nn = (NacosNamingService *) n;\r\n    NamingProxy *namingProxy = nn->getServerProxy();\r\n\r\n    //Create a clean environment\r\n    bool healthy;\r\n    try {\r\n        healthy = namingProxy->serverHealthy();\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"Exception caught during deregistering service, raison:\" << e.what() << endl;\r\n\r\n        return false;\r\n    }\r\n\r\n    if (healthy) {\r\n        cout << \"server healthy\" << endl;\r\n    } else {\r\n\r\n        cout << \"server down\" << endl;\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\nbool testNamingProxyFailOver() {\r\n    cout << \"in function testNamingProxyFailOver\" << endl;\r\n    return true;\r\n}\r\n\r\nclass NamingServiceSelector : public naming::selectors::Selector<Instance> {\r\nprivate:\r\n    int _port;\r\npublic:\r\n    void setSelectPort(int port) { _port = port; };\r\n    list<Instance> select(const std::list<Instance> &itemsToSelect) {\r\n        list<Instance> res;\r\n        for (list<Instance>::const_iterator it = itemsToSelect.begin();\r\n        it != itemsToSelect.end(); it++) {\r\n            if ((*it).port == _port) {\r\n                res.push_back(*it);\r\n            }\r\n        }\r\n\r\n        return res;\r\n    }\r\n};\r\n\r\nbool testNamingServiceRegister() {\r\n    cout << \"in function testNamingServiceRegister\" << endl;\r\n    Properties configProps;\r\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\r\n    ADD_AUTH_INFO(configProps);\r\n    ADD_SPAS_INFO(configProps);\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    NamingService *namingSvc = factory->CreateNamingService();\r\n    ResourceGuard <NamingService> _serviceFactory(namingSvc);\r\n    Instance instance;\r\n    instance.clusterName = \"DefaultCluster\";\r\n    instance.ip = \"127.0.0.1\";\r\n    instance.port = 2333;\r\n    instance.instanceId = \"1\";\r\n    instance.ephemeral = true;\r\n\r\n    try {\r\n        for (int i = 0; i < NR_SERVICES; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            for (int j = 0; j < NR_SERVICE_INSTS; j++) {\r\n                instance.clusterName = \"DefaultCluster\";\r\n                instance.ip = \"127.0.0.1\";\r\n                instance.port = 20000 + i*NR_SERVICE_INSTS+j;\r\n                instance.instanceId = NacosStringOps::valueOf(i * NR_SERVICE_INSTS + j);\r\n                instance.ephemeral = true;\r\n                namingSvc->registerInstance(serviceName, instance);\r\n            }\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    sleep(5);\r\n\r\n    try {\r\n        for (int i = 0; i < NR_SERVICES; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            for (int j = 0; j < NR_SERVICE_INSTS; j++) {\r\n                NamingServiceSelector selector;\r\n                selector.setSelectPort(20000 + i*NR_SERVICE_INSTS+j);\r\n                list<Instance> instanceList = namingSvc->getInstanceWithPredicate(serviceName, &selector);\r\n                if (!instanceList.empty()) {\r\n                    cout << (i*NR_SERVICE_INSTS+j) << \":Instance info got from server:\" << instanceList.begin()->toString() << endl;\r\n                } else {\r\n                    cout << \"Got empty instance list from server!\" << endl;\r\n                    return false;\r\n                }\r\n                SHOULD_BE_TRUE(instanceList.size() == 1, \"There should be only 1 instance for each port\");\r\n                SHOULD_BE_TRUE(instanceList.begin()->clusterName == \"DefaultCluster\", \"Cluster name should be DefaultCluster\");\r\n                SHOULD_BE_TRUE(instanceList.begin()->ephemeral == true, \"Should be ephemeral node\");\r\n            }\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while getting service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    cout << \"testNamingServiceRegister successful\" << endl;\r\n\r\n    return true;\r\n}\r\n\r\nbool testNamingServiceAndDeRegisterActively() {\r\n    cout << \"in function testNamingServiceAndDeRegisterActively\" << endl;\r\n    Properties configProps;\r\n    configProps[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1\";\r\n    ADD_AUTH_INFO(configProps);\r\n    ADD_SPAS_INFO(configProps);\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(configProps);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    NamingService *namingSvc = factory->CreateNamingService();\r\n    ResourceGuard <NamingService> _serviceFactory(namingSvc);\r\n    Instance instance;\r\n    instance.clusterName = \"DefaultCluster\";\r\n    instance.ip = \"127.0.0.1\";\r\n    instance.port = 2333;\r\n    instance.instanceId = \"1\";\r\n    instance.ephemeral = true;\r\n\r\n    try {\r\n        for (int i = 0; i < NR_SERVICES; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            for (int j = 0; j < NR_SERVICE_INSTS; j++) {\r\n                instance.clusterName = \"DefaultCluster\";\r\n                instance.ip = \"127.0.0.1\";\r\n                instance.port = 20000 + i*NR_SERVICE_INSTS+j;\r\n                instance.instanceId = NacosStringOps::valueOf(i * NR_SERVICE_INSTS + j);\r\n                instance.ephemeral = true;\r\n                namingSvc->registerInstance(serviceName, instance);\r\n            }\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while registering service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    sleep(5);\r\n\r\n    try {\r\n        for (int i = 0; i < NR_SERVICES; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            for (int j = 0; j < NR_SERVICE_INSTS; j++) {\r\n                NamingServiceSelector selector;\r\n                selector.setSelectPort(20000 + i*NR_SERVICE_INSTS+j);\r\n                list<Instance> instanceList = namingSvc->getInstanceWithPredicate(serviceName, &selector);\r\n                if (!instanceList.empty()) {\r\n                    cout << (i*NR_SERVICE_INSTS+j) << \":Instance info got from server:\" << instanceList.begin()->toString() << endl;\r\n                } else {\r\n                    cout << \"Got empty instance list from server!\" << endl;\r\n                    return false;\r\n                }\r\n                SHOULD_BE_TRUE(instanceList.size() == 1, \"There should be only 1 instance for each port\");\r\n                SHOULD_BE_TRUE(instanceList.begin()->clusterName == \"DefaultCluster\", \"Cluster name should be DefaultCluster\");\r\n                SHOULD_BE_TRUE(instanceList.begin()->ephemeral == true, \"Should be ephemeral node\");\r\n            }\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while getting service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    try {\r\n        for (int i = 0; i < NR_SERVICES; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            for (int j = 0; j < NR_SERVICE_INSTS; j++) {\r\n                NamingServiceSelector selector;\r\n                selector.setSelectPort(20000 + i*NR_SERVICE_INSTS+j);\r\n                namingSvc->deregisterInstance(serviceName, \"127.0.0.1\", 20000 + i*NR_SERVICE_INSTS+j);\r\n            }\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while getting service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    cout << \"wait for 40 secs to make sure all instances are removed from nacos server\" << endl;\r\n    sleep(40);\r\n\r\n    try {\r\n        for (int i = 0; i < NR_SERVICES; i++) {\r\n            NacosString serviceName = \"TestNamingService\" + NacosStringOps::valueOf(i);\r\n            for (int j = 0; j < NR_SERVICE_INSTS; j++) {\r\n                NamingServiceSelector selector;\r\n                selector.setSelectPort(20000 + i*NR_SERVICE_INSTS+j);\r\n                list<Instance> instanceList = namingSvc->getInstanceWithPredicate(serviceName, &selector);\r\n\r\n                SHOULD_BE_TRUE(instanceList.empty(), \"There shouldn't be any instance since removed\");\r\n            }\r\n        }\r\n    }\r\n    catch (NacosException &e) {\r\n        cout << \"encounter exception while getting service instance, raison:\" << e.what() << endl;\r\n        return false;\r\n    }\r\n\r\n    cout << \"testNamingServiceAndDeRegisterActively successful\" << endl;\r\n\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testNamingSubscribe.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"naming/subscribe/EventListener.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nclass MyServiceListener : public EventListener {\nprivate:\n    int num;\npublic:\n    MyServiceListener(int num) {\n        this->num = num;\n    }\n\n    void receiveNamingInfo(const ServiceInfo &serviceInfo){\n        cout << \"===================================\" << endl;\n        cout << \"Watcher: \" << num << endl;\n        cout << \"Watched service UPDATED: \" << serviceInfo.toInstanceString() << endl;\n        cout << \"===================================\" << endl;\n\n    }\n};\n\nbool testListenService() {\n    cout << \"in function testListenService\" << endl;\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    props[PropertyKeyConst::LOCAL_IP] = \"127.0.0.1\";\n    ADD_AUTH_INFO(props);\n    ADD_SPAS_INFO(props);\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *n = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(n);\n\n    n->subscribe(\"ss\", new MyServiceListener(1));\n\n    n->registerInstance(\"ss\", \"127.0.0.1\", 33);\n    n->registerInstance(\"ss\", \"127.0.0.1\", 34);\n\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 33);\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 34);\n\n    n->registerInstance(\"ss\", \"127.0.0.1\", 33);\n    n->registerInstance(\"ss\", \"127.0.0.1\", 34);\n\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 33);\n    n->deregisterInstance(\"ss\", \"127.0.0.1\", 34);\n\n    cout << \"All instances Unregistered\" << endl;\n\n    return true;\n}\n\n//testcase for bugfix#101, if the problem persists, this function will cause a coredump\nbool testSubscribeAlotOfServices() {\n    cout << \"in function testSubscribeAlotOfServices\" << endl;\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    props[PropertyKeyConst::LOCAL_IP] = \"127.0.0.1\";\n    props[PropertyKeyConst::LOG_LEVEL] = \"WARN\";\n    ADD_AUTH_INFO(props);\n    ADD_SPAS_INFO(props);\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    NamingService *n = factory->CreateNamingService();\n    ResourceGuard <NamingService> _serviceFactory(n);\n\n    n->subscribe(\"ss\", new MyServiceListener(1));\n\n    for (int i = 0; i < 1000; i++) {\n\n        n->registerInstance(\"ss\", \"127.0.0.1\", 2000+i);\n    }\n\n    sleep(20);\n\n    for (int i = 0; i < 1000; i++) {\n        n->deregisterInstance(\"ss\", \"127.0.0.1\", 2000+i);\n    }\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testNetUtils.cpp",
    "content": "#include <iostream>\n#include \"src/utils//NetUtils.h\"\n#include \"src/debug/DebugAssertion.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testGetHostIp() {\n    cout << \"in function testGetHostIp\" << endl;\n\n    NacosString ip = NetUtils::getHostIp();\n    cout << \"ip:\" << ip << endl;\n    SHOULD_BE_TRUE(!ip.empty(), \"Ip got for local machine should not be empty\");\n    cout << \"test end...\" << endl;\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testPublishConfig.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include <stdio.h>\r\n#include <unistd.h>\r\n#include \"factory/NacosFactoryFactory.h\"\r\n#include \"ResourceGuard.h\"\r\n#include \"constant/PropertyKeyConst.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testPublishConfig() {\r\n    cout << \"in function testPublishConfig\" << endl;\r\n    Properties props;\r\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\r\n    ADD_AUTH_INFO(props);\r\n    ADD_SPAS_INFO(props);\r\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\r\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\r\n    ConfigService *n = factory->CreateConfigService();\r\n    ResourceGuard <ConfigService> _serviceFactory(n);\r\n    bool bSucc;\r\n    for (int i = 0; i < 50; i++) {\r\n        char key_s[200];\r\n        char val_s[200];\r\n        snprintf(key_s, sizeof(key_s), \"Key%d\", i);\r\n        snprintf(val_s, sizeof(val_s), \"v__%d\", i);\r\n        NacosString ss = \"\";\r\n\r\n        try {\r\n            bSucc = n->publishConfig(key_s, NULLSTR, val_s);\r\n            int retry = 0;\r\n            while (!(ss == val_s) && retry++ < 10) {\r\n                sleep(1);\r\n                try {\r\n                    ss = n->getConfig(key_s, NULLSTR, 1000);\r\n                } catch (NacosException & ignore) {\r\n                    //getConfig may throw 404, but that doesn't matter\r\n                }\r\n            }\r\n\r\n            if (!(ss == val_s)) {\r\n                throw NacosException(0, \"getConfig() failed.\");\r\n            }\r\n        }\r\n        catch (NacosException &e) {\r\n            cout <<\r\n                 \"Request failed with curl code:\" << e.errorcode() << endl <<\r\n                 \"Reason:\" << e.what() << endl;\r\n\r\n            return false;\r\n        }\r\n        cout << \"Publishing Key:\" << key_s << \" with value:\" << val_s << \" result:\" << bSucc << endl;\r\n    }\r\n\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testPublishConfigWithHttpPrefix.cpp",
    "content": "#include <iostream>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/log/Logger.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testPublishConfigWithHttpPrefix() {\n    cout << \"in function testPublishConfigWithHttpPrefix\" << endl;\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"htTp://localhost:8848,HtTP://127.0.0.1:8848\";\n    ADD_AUTH_INFO(props);\n    ADD_SPAS_INFO(props);\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n    bool bSucc;\n    for (int i = 0; i < 50; i++) {\n        char key_s[200];\n        char val_s[200];\n        snprintf(key_s, sizeof(key_s), \"Key%d\", i);\n        snprintf(val_s, sizeof(val_s), \"v__%d\", i);\n        NacosString ss = \"\";\n\n        try {\n            bSucc = n->publishConfig(key_s, NULLSTR, val_s);\n            int retry = 0;\n            while (!(ss == val_s) && retry++ < 10) {\n                sleep(1);\n                try {\n                    ss = n->getConfig(key_s, NULLSTR, 1000);\n                } catch (NacosException &e) { }\n            }\n            n->removeConfig(key_s, NULLSTR);\n\n            if (!(ss == val_s)) {\n                throw NacosException(0, \"getConfig() failed.\");\n            }\n        }\n        catch (NacosException &e) {\n            cout <<\n                 \"Request failed with curl code:\" << e.errorcode() << endl <<\n                 \"Reason:\" << e.what() << endl;\n\n            return false;\n        }\n        cout << \"Publishing Key:\" << key_s << \" with value:\" << val_s << \" result:\" << bSucc << endl;\n    }\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testRapidJson.cpp",
    "content": "#include <iostream>\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/json/rapidjson/document.h\"\r\n#include \"src/json/rapidjson/writer.h\"\r\n#include \"src/json/rapidjson/stringbuffer.h\"\r\n#include \"src/naming/beat/BeatInfo.h\"\r\n#include \"src/json/JSON.h\"\r\n\r\nusing namespace std;\r\nusing namespace rapidjson;\r\nusing namespace nacos;\r\n\r\nbool testRapidJsonIntroduce() {\r\n    // 1. 把 JSON 解析至 DOM。\r\n    const char *json = \"{\\\"project\\\":\\\"rapidjson\\\",\\\"stars\\\":10}\";\r\n    Document d;\r\n    d.Parse(json);\r\n    // 2. 利用 DOM 作出修改。\r\n    Value &s = d[\"stars\"];\r\n    s.SetInt(s.GetInt() + 1);\r\n    // 3. 把 DOM 转换（stringify）成 JSON。\r\n    StringBuffer buffer;\r\n    Writer <StringBuffer> writer(buffer);\r\n    d.Accept(writer);\r\n    // Output {\"project\":\"rapidjson\",\"stars\":11}\r\n    std::cout << buffer.GetString() << std::endl;\r\n\r\n    Document parsedAgain;\r\n    parsedAgain.Parse(buffer.GetString());\r\n    Value &s2 = parsedAgain[\"stars\"];\r\n    int expectedtoBe11 = s2.GetInt();\r\n    SHOULD_BE_TRUE(expectedtoBe11 == 11, \"There should be 11 stars\");\r\n\r\n    return true;\r\n}\r\n\r\nbool testSerialize() {\r\n    BeatInfo bi;\r\n    bi.port = 10;\r\n    cout << JSON::toJSONString(bi);\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testSequenceProvider.cpp",
    "content": "#include <iostream>\n#include \"src/thread/Thread.h\"\n#include \"src/utils/SequenceProvider.h\"\n#include \"src/utils/DirUtils.h\"\n\nusing namespace std;\nusing namespace nacos;\n\n#define NR_THREADS 200\n#define GENERATION_PER_THREAD 1000\n\nint64_t sequences[GENERATION_PER_THREAD * NR_THREADS];\nint tid[NR_THREADS];\n\nSequenceProvider<uint64_t> *sequenceProvider;\n\nvoid *SeqThreadFunc(void *param) {\n    int *thread_no = (int*)param;\n    for (int i = 0; i < GENERATION_PER_THREAD; i++) {\n        int64_t res = sequenceProvider->next();\n        sequences[(*thread_no) * GENERATION_PER_THREAD + i] = res;\n    }\n\n    return NULL;\n}\n\nbool testSequenceProvider() {\n    cout << \"in function testSequenceProvider\" << endl;\n\n    cout << \"Generating SEQ...\" << endl;\n\n    sequenceProvider = new SequenceProvider<uint64_t> (DirUtils::getCwd() + \"/test_seq.dat\", 20000, 100);\n\n    Thread *threads[NR_THREADS] = {NULL};\n    for (int i = 0; i < NR_THREADS; i++) {\n        NacosString threadName = \"SEQThread-\" + NacosStringOps::valueOf(i);\n        tid[i] = i;\n        threads[i] = new Thread(threadName, SeqThreadFunc, (void *) &tid[i]);\n        threads[i]->start();\n    }\n\n    for (int i = 0; i < NR_THREADS; i++) {\n        threads[i]->join();\n        delete threads[i];\n    }\n\n    cout << \"Generated.\" << endl;\n\n    for (int i = 0; i < NR_THREADS; i++) {\n        for (int j = 0; j < GENERATION_PER_THREAD; j++) {\n            cout << \"Thread \" << i << \": sequence =\\t\" << sequences[i * GENERATION_PER_THREAD + j] << endl;\n        }\n    }\n\n    cout << \"test end...\" << endl;\n\n    return true;\n}\n"
  },
  {
    "path": "test/testcase/testServerListManager.cpp",
    "content": "#include <iostream>\n#include <map>\n#include \"src/server/ServerListManager.h\"\n#include \"src/config/NacosConfigService.h\"\n#include \"factory/NacosFactoryFactory.h\"\n#include \"ResourceGuard.h\"\n#include \"src/http/HTTPCli.h\"\n#include \"constant/PropertyKeyConst.h\"\n#include \"src/json/JSON.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testServerListManager() {\n    cout << \"in function testServerListManager\" << endl;\n    Properties props;\n    props[PropertyKeyConst::SERVER_ADDR] = \"127.0.0.1:8848\";\n    INacosServiceFactory *factory = NacosFactoryFactory::getNacosFactory(props);\n    ResourceGuard <INacosServiceFactory> _guardFactory(factory);\n    ConfigService *n = factory->CreateConfigService();\n    ResourceGuard <ConfigService> _serviceFactory(n);\n\n    //NacosConfigService *nn = (NacosConfigService *) n;\n    //ServerListManager *serverListManager = nn->getServerListManager();\n\n    list <NacosServerInfo> res;// = serverListManager->__debug();\n\n    for (list<NacosServerInfo>::iterator it = res.begin(); it != res.end(); it++) {\n        NacosString key = it->getKey();\n        NacosString val = it->getCompleteAddress();\n\n        cout << key << \":\" << endl << val << endl;\n    }\n\n    cout << \"=====================cornercase========================\" << endl;\n    NacosString fakeSvr = \"{\\\"servers\\\":[]}\";\n    list <NacosServerInfo> result = JSON::Json2NacosServerInfo(fakeSvr);\n    cout << \"result.size == \" << result.size() << endl;\n    for (list<NacosServerInfo>::iterator it = result.begin(); it != result.end(); it++) {\n        NacosString key = it->getCompleteAddress();\n        NacosString val = it->toString();\n\n        cout << key << \":\" << endl << val << endl;\n    }\n    return true;\n}"
  },
  {
    "path": "test/testcase/testStringExplode.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include <list>\r\n#include \"src/utils/ParamUtils.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testStringExplode() {\r\n    cout << \"in function testStringExplode\" << endl;\r\n\r\n    vector <NacosString> explodedList;\r\n    NacosString originalContent = \"Hello|World|My|Name|Is\";\r\n    ParamUtils::Explode(explodedList, originalContent, '|');\r\n    SHOULD_BE_TRUE(explodedList.size() == 5,\r\n                   \"Exploding Hello|World|My|Name|Is with separator | should get a list with size 5.\");\r\n    SHOULD_BE_TRUE(explodedList[0] == \"Hello\", \"explodedList[0] should be Hello\");\r\n    SHOULD_BE_TRUE(explodedList[1] == \"World\", \"explodedList[1] should be World\");\r\n    SHOULD_BE_TRUE(explodedList[2] == \"My\", \"explodedList[2] should be My\");\r\n    SHOULD_BE_TRUE(explodedList[3] == \"Name\", \"explodedList[3] should be Name\");\r\n    SHOULD_BE_TRUE(explodedList[4] == \"Is\", \"explodedList[4] should be Is\");\r\n\r\n    vector <NacosString> specialExplode;\r\n    NacosString specialoriginalContent = \"Hello\\x1World\\x1My\\x1Name\\x1Is\";\r\n    ParamUtils::Explode(specialExplode, specialoriginalContent, '\\x1');\r\n    SHOULD_BE_TRUE(specialExplode.size() == 5,\r\n                   \"Exploding Hello\\x1World\\x1My\\x1Name\\x1Is with separator \\x1 should get a list with size 5.\");\r\n    SHOULD_BE_TRUE(specialExplode[0] == \"Hello\", \"specialExplode[0] should be Hello\");\r\n    SHOULD_BE_TRUE(specialExplode[1] == \"World\", \"specialExplode[1] should be World\");\r\n    SHOULD_BE_TRUE(specialExplode[2] == \"My\", \"specialExplode[2] should be My\");\r\n    SHOULD_BE_TRUE(specialExplode[3] == \"Name\", \"specialExplode[3] should be Name\");\r\n    SHOULD_BE_TRUE(specialExplode[4] == \"Is\", \"specialExplode[4] should be Is\");\r\n\r\n    vector <NacosString> nullEnd;\r\n    NacosString nullEndStr = \"k=\";\r\n    ParamUtils::Explode(nullEnd, nullEndStr, '=');\r\n    SHOULD_BE_TRUE(nullEnd.size() == 2, \"exploding k= should get 2 items\");\r\n    SHOULD_BE_TRUE(nullEnd[0] == \"k\", \"nullEnd[0] should be k\");\r\n    SHOULD_BE_TRUE(nullEnd[1] == \"\", \"nullEnd[0] should be empty\");\r\n\r\n    return true;\r\n}\r\n\r\nbool testStringExplode2() {\r\n    cout << \"in function testStringExplode2 - enhanced one which can handle string separator\" << endl;\r\n\r\n    vector <NacosString> explodedList;\r\n    NacosString originalContent = \"Hello||World||My||Name||Is\";\r\n    ParamUtils::Explode(explodedList, originalContent, \"||\");\r\n    SHOULD_BE_TRUE(explodedList.size() == 5,\r\n                   \"Exploding Hello||World||My||Name||Is with separator || should get a list with size 5.\");\r\n    SHOULD_BE_TRUE(explodedList[0] == \"Hello\", \"explodedList[0] should be Hello\");\r\n    SHOULD_BE_TRUE(explodedList[1] == \"World\", \"explodedList[1] should be World\");\r\n    SHOULD_BE_TRUE(explodedList[2] == \"My\", \"explodedList[2] should be My\");\r\n    SHOULD_BE_TRUE(explodedList[3] == \"Name\", \"explodedList[3] should be Name\");\r\n    SHOULD_BE_TRUE(explodedList[4] == \"Is\", \"explodedList[4] should be Is\");\r\n\r\n    vector <NacosString> specialExplode;\r\n    NacosString specialoriginalContent = \"Hello\\x1\\x1World\\x1\\x1My\\x1\\x1Name\\x1\\x1Is\\x1\\x1\";\r\n    ParamUtils::Explode(specialExplode, specialoriginalContent, \"\\x1\\x1\");\r\n    SHOULD_BE_TRUE(specialExplode.size() == 6,\r\n                   \"Exploding Hello\\x1\\x1World\\x1\\x1My\\x1\\x1Name\\x1\\x1Is\\x1\\x1 with separator \\x1\\x1 should get a list with size 5.\");\r\n    SHOULD_BE_TRUE(specialExplode[0] == \"Hello\", \"specialExplode[0] should be Hello\");\r\n    SHOULD_BE_TRUE(specialExplode[1] == \"World\", \"specialExplode[1] should be World\");\r\n    SHOULD_BE_TRUE(specialExplode[2] == \"My\", \"specialExplode[2] should be My\");\r\n    SHOULD_BE_TRUE(specialExplode[3] == \"Name\", \"specialExplode[3] should be Name\");\r\n    SHOULD_BE_TRUE(specialExplode[4] == \"Is\", \"specialExplode[4] should be Is\");\r\n\r\n    vector <NacosString> nullEnd;\r\n    NacosString nullEndStr = \"k==\";\r\n    ParamUtils::Explode(nullEnd, nullEndStr, \"==\");\r\n    SHOULD_BE_TRUE(nullEnd.size() == 2, \"exploding k== should get 2 items\");\r\n    SHOULD_BE_TRUE(nullEnd[0] == \"k\", \"nullEnd[0] should be k\");\r\n    SHOULD_BE_TRUE(nullEnd[1] == \"\", \"nullEnd[0] should be empty\");\r\n\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testThreadLocal.cpp",
    "content": "#include <iostream>\n#include \"src/utils/UuidUtils.h\"\n#include \"src/thread/Thread.h\"\n#include \"src/thread/ThreadLocal.h\"\n#include \"src/debug/DebugAssertion.h\"\n#include \"src/utils/RandomUtils.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nThreadLocal<NacosString> threadLocal;\nThreadLocal<int*> threadLocalPtr(NULL);\n\nclass ThreadLocalWithInit : public ThreadLocal<int*> {\npublic:\n    void onCreate(int **value){\n        *value = (int*)0xffff;\n        log_debug(\"ThreadLocalWithInit::onCreate is called, ptr value: %p\\n\", *value);\n    }\n\n    void onDestroy(int **value) {\n        log_debug(\"ThreadLocalWithInit::onDestroy is called, ptr value: %p\\n\", *value);\n    }\n};\n\nThreadLocalWithInit threadLocalPtrWithInitializer;\n\nvoid *ThreadLocalFuncs4Ptr(void *param) {\n    log_debug(\"threadLocalPtr.get() : %p, should be null\\n\", threadLocalPtr.get());\n    NACOS_ASSERT(threadLocalPtr.get() == NULL);\n\n    for (int i = 0; i < 100; i++) {\n        int* rndPtr = reinterpret_cast<int*>(RandomUtils::random(0, 1000));\n        threadLocalPtr.set(rndPtr);\n\n        NACOS_ASSERT(rndPtr == threadLocalPtr.get())\n    }\n\n    return NULL;\n}\n\nvoid *ThreadLocalFuncs4PtrWithInitializer(void *param) {\n    log_debug(\"threadLocalPtr.get() : %p, should be 0xFFFF\\n\", threadLocalPtrWithInitializer.get());\n    NACOS_ASSERT(threadLocalPtrWithInitializer.get() == (int*)0xFFFF);\n\n    for (int i = 0; i < 100; i++) {\n        int* rndPtr = reinterpret_cast<int*>(RandomUtils::random(0, 1000));\n        threadLocalPtrWithInitializer.set(rndPtr);\n\n        NACOS_ASSERT(rndPtr == threadLocalPtrWithInitializer.get())\n    }\n\n    return NULL;\n}\n\nvoid *ThreadLocalFuncs(void *param) {\n    Thread *thisThread = *((Thread **) param);\n\n    for (int i = 0; i < 100; i++) {\n        threadLocal.set(UuidUtils::generateUuid().c_str());\n        log_debug(\"Thread %s UUID: %s\\n\", thisThread->getThreadName().c_str(), threadLocal.get().c_str());\n    }\n\n    return NULL;\n}\n\nbool testThreadLocal() {\n    cout << \"in function testThreadLocal\" << endl;\n\n    cout << \"Generating threads...\" << endl;\n\n    Thread *threads[10] = {NULL};\n    for (int i = 0; i < 10; i++) {\n        NacosString threadName = \"Thread-\" + NacosStringOps::valueOf(i);\n        threads[i] = new Thread(threadName, ThreadLocalFuncs, (void *) &threads[i]);\n        threads[i]->start();\n    }\n\n    for (int i = 0; i < 10; i++) {\n        threads[i]->join();\n        delete threads[i];\n    }\n\n    cout << \"test end...\" << endl;\n\n    return true;\n}\n\nbool testThreadLocalPtr() {\n    cout << \"in function testThreadLocalPtr\" << endl;\n\n    cout << \"Generating threads...\" << endl;\n\n    Thread *threads[10] = {NULL};\n    for (int i = 0; i < 10; i++) {\n        NacosString threadName = \"ThreadPtr-\" + NacosStringOps::valueOf(i);\n        threads[i] = new Thread(threadName, ThreadLocalFuncs4Ptr, (void *) &threads[i]);\n        threads[i]->start();\n    }\n\n    for (int i = 0; i < 10; i++) {\n        threads[i]->join();\n        delete threads[i];\n    }\n\n    cout << \"test end...\" << endl;\n\n    return true;\n}\n\nbool testThreadLocalPtrWithInitializer() {\n    cout << \"in function testThreadLocalPtrWithInitializer\" << endl;\n\n    cout << \"Generating threads...\" << endl;\n\n    Thread *threads[10] = {NULL};\n    for (int i = 0; i < 10; i++) {\n        NacosString threadName = \"ThreadPtr-\" + NacosStringOps::valueOf(i);\n        threads[i] = new Thread(threadName, ThreadLocalFuncs4PtrWithInitializer, (void *) &threads[i]);\n        threads[i]->start();\n    }\n\n    for (int i = 0; i < 10; i++) {\n        threads[i]->join();\n        delete threads[i];\n    }\n\n    cout << \"test end...\" << endl;\n\n    return true;\n}"
  },
  {
    "path": "test/testcase/testThreadSmoke.cpp",
    "content": "#include <iostream>\r\n#include <unistd.h>\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/log/Logger.h\"\r\n#include \"src/thread/Thread.h\"\r\n#include \"src/thread/ThreadPool.h\"\r\n#include \"NacosString.h\"\r\n#include \"thread/AtomicInt.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nclass ThreadPoolLongRunTask : public Task {\r\n\r\npublic:\r\n    ThreadPoolLongRunTask(int taskId) {\r\n        NacosString taskName = \"ThreadPoolLongRunTask\" + NacosStringOps::valueOf(taskId);\r\n        setTaskName(taskName);\r\n    };\r\n\r\n    void run() {\r\n        NacosString taskName = getTaskName();\r\n        log_info(\"Hello world from %s\\n\", taskName.c_str());\r\n        log_info(\"Run for 10 secs\\n\");\r\n        sleep(5);\r\n        log_info(\"ok\\n\");\r\n    };\r\n};\r\n\r\nvoid *threadFunc(void *param) {\r\n    log_info(\"Hello from threadFunc() in another thread, stopping threadpool\\n\");\r\n    return NULL;\r\n}\r\n\r\nbool testThreadSmoke() {\r\n    cout << \"In testThreadSmoke\" << endl;\r\n    Thread t(\"testThread\", threadFunc);\r\n    t.start();\r\n    t.join();\r\n\r\n    cout << \"If no coredump, should be successful\" << endl;\r\n\r\n    return true;\r\n}\r\n\r\nvoid *threadStopper(void *param) {\r\n    ThreadPool *tp = (ThreadPool *) param;\r\n    log_info(\"Hello from threadStopper() in another thread, stopping threadpool\\n\");\r\n    sleep(10);\r\n    tp->stop();\r\n    log_info(\"threadStopper():ok\\n\");\r\n    return NULL;\r\n}\r\n\r\nbool testThreadPoolSmoke() {\r\n    cout << \"Starting testThreadPoolSmoke...\" << endl;\r\n    ThreadPool tp(10);\r\n    tp.start();\r\n    cout << \"ok, size = 32\" << endl;\r\n\r\n    Thread tpStopper(\"tpStopper\", threadStopper, &tp);\r\n    tpStopper.start();\r\n\r\n    Task *tasks[1000];\r\n    for (size_t i = 0; i < 40; i++) {\r\n        cout << \"Creating task \" << i << \"...\" << endl;\r\n        tasks[i] = new ThreadPoolLongRunTask(i);\r\n        tp.put(tasks[i]);\r\n        cout << \"ok\" << endl;\r\n    }\r\n\r\n    tp.stop();\r\n    for (size_t i = 0; i < 40; i++) {\r\n        cout << \"destroying task \" << i << \"...\" << endl;\r\n        delete tasks[i];\r\n        tasks[i] = NULL;\r\n        cout << \"ok\" << endl;\r\n    }\r\n    cout << \"If no coredump, should be successful\" << endl;\r\n    tpStopper.join();\r\n\r\n    return true;\r\n}\r\n\r\nAtomicInt<int> totalFinishedThreads;\r\n\r\nclass SmokingTestThreadTask : public Task {\r\nprivate:\r\n    AtomicInt<int> &_counter;\r\npublic:\r\n    SmokingTestThreadTask(const NacosString &taskName, AtomicInt<int> &counter) : _counter(counter) {\r\n        setTaskName(taskName);\r\n    };\r\n\r\n    void run() {\r\n        NacosString taskName = getTaskName();\r\n        int currentTotal = 0;\r\n        for (int i = 0; i < 100000; i++) {\r\n            currentTotal = _counter.inc();\r\n        }\r\n        log_info(\"Hello world from %s, totalCount = %d\\n\", taskName.c_str(), currentTotal);\r\n        totalFinishedThreads.inc();\r\n    };\r\n};\r\n\r\nbool testThreadPoolConcurrentWithAtomicCounter() {\r\n    cout << \"Starting testThreadPoolConcurrentWithAtomicCounter...\" << endl;\r\n    ThreadPool tp(10);\r\n    tp.start();\r\n    cout << \"ok, size = 10\" << endl;\r\n    AtomicInt<int> totalCounter;\r\n\r\n    Task *tasks[1000];\r\n    for (size_t i = 0; i < 40; i++) {\r\n        cout << \"Creating task \" << i << \"...\" << endl;\r\n        tasks[i] = new SmokingTestThreadTask(\"Counter-\" + NacosStringOps::valueOf(i), totalCounter);\r\n        tp.put(tasks[i]);\r\n        cout << \"ok\" << endl;\r\n    }\r\n\r\n\r\n    while (totalFinishedThreads.get() != 40) {\r\n        sleep(1);\r\n    }\r\n    tp.stop();\r\n    cout << \"If no coredump, should be successful\" << endl;\r\n    cout << \"totalCounter.get() = \" << totalCounter.get() << endl;\r\n\r\n    SHOULD_BE_TRUE(totalCounter.get() == 40 * 100000, \"40 threads, each thread accumulates totalCounter by 100k, result should be 4000k\");\r\n\r\n    for (size_t i = 0; i < 40; i++) {\r\n        cout << \"destroying task \" << i << \"...\" << endl;\r\n        delete tasks[i];\r\n        tasks[i] = NULL;\r\n        cout << \"ok\" << endl;\r\n    }\r\n    return true;\r\n}"
  },
  {
    "path": "test/testcase/testURL.cpp",
    "content": "#include <iostream>\r\n#include <stdlib.h>\r\n#include \"src/utils/url.h\"\r\n#include \"src/debug/DebugAssertion.h\"\r\n#include \"src/log/Logger.h\"\r\n\r\nusing namespace std;\r\nusing namespace nacos;\r\n\r\nbool testURLEncodeAndDecode() {\r\n    cout << \"in function testURLEncode\" << endl;\r\n\r\n    NacosString originalContent = \"Hello W! orld \\\\/,.%$@^%#*43543\";\r\n    NacosString encoded = urlencode(originalContent);\r\n    cout << \"Encoded:\" << encoded << endl;\r\n    NacosString decoded = urldecode(encoded);\r\n    SHOULD_BE_TRUE(originalContent == decoded, \"After encoding and decoding, the content should remain the same.\");\r\n\r\n    return true;\r\n}\r\n"
  },
  {
    "path": "test/testcase/testUUID.cpp",
    "content": "#include <iostream>\n#include \"src/utils//UuidUtils.h\"\n#include \"src/thread/Thread.h\"\n\nusing namespace std;\nusing namespace nacos;\n\nbool testUUID() {\n    cout << \"in function testUUID\" << endl;\n\n    cout << \"Generating UUID...\" << endl;\n    for (int i = 0; i < 100; i++) {\n        cout << \"UUID:\" << UuidUtils::generateUuid() << endl;\n    }\n    cout << \"test end...\" << endl;\n\n    return true;\n}\n\nvoid *UUIDThreadFunc(void *param) {\n    Thread *thisThread = *((Thread **) param);\n    for (int i = 0; i < 100; i++) {\n        log_debug(\"Thread %s UUID: %s\\n\", thisThread->getThreadName().c_str(), UuidUtils::generateUuid().c_str());\n    }\n\n    return NULL;\n}\n\nbool testUUIDMT() {\n    cout << \"in function testUUIDMT\" << endl;\n\n    cout << \"Generating UUID...\" << endl;\n\n    Thread *threads[10] = {NULL};\n    for (int i = 0; i < 10; i++) {\n        NacosString threadName = \"UUIDThread-\" + NacosStringOps::valueOf(i);\n        threads[i] = new Thread(threadName, UUIDThreadFunc, (void *) &threads[i]);\n        threads[i]->start();\n    }\n\n    for (int i = 0; i < 10; i++) {\n        threads[i]->join();\n        delete threads[i];\n    }\n\n    cout << \"test end...\" << endl;\n\n    return true;\n}\n"
  }
]