├── assets ├── logo.png └── example.png ├── tests ├── main.cpp ├── test_basic_config │ ├── common.h │ ├── test_iterator.cpp │ ├── test_conversion.cpp │ └── test_basic.cpp ├── data │ └── json.org │ │ ├── 2.json │ │ ├── 1.json │ │ ├── 3.json │ │ ├── 5.json │ │ └── 4.json ├── test_json │ ├── common.h │ ├── test_unicode.cpp │ ├── test_serializer.cpp │ └── test_parser.cpp ├── CMakeLists.txt └── 3rd-party │ ├── fifo_map │ ├── LICENSE.MIT │ └── fifo_map.hpp │ └── catch2 │ └── LICENSE.txt ├── examples ├── CMakeLists.txt ├── main.cpp ├── user_info.cpp ├── user_info.h └── handler.h ├── codecov.yml ├── .editorconfig ├── .gitignore ├── LICENSE ├── CMakeLists.txt ├── cmake ├── llvm-cov-wrapper ├── FindGcov.cmake ├── Findcodecov.cmake └── FindLcov.cmake ├── include └── configor │ ├── configor.hpp │ └── details │ ├── token.hpp │ ├── exception.hpp │ ├── wrapper.hpp │ ├── declare.hpp │ ├── serializer.hpp │ ├── parser.hpp │ ├── stream.hpp │ └── encoding.hpp ├── README-zh.md ├── README.md ├── .clang-format └── .github └── workflows └── unit_tests.yml /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nomango/configor/HEAD/assets/logo.png -------------------------------------------------------------------------------- /assets/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nomango/configor/HEAD/assets/example.png -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Nomango 2 | 3 | #define CATCH_CONFIG_MAIN 4 | #include 5 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. SOURCES) 2 | 3 | add_executable(${PROJECT_NAME}_example ${SOURCES}) 4 | -------------------------------------------------------------------------------- /tests/test_basic_config/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | using namespace configor; 9 | -------------------------------------------------------------------------------- /tests/data/json.org/2.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "id": "file", 3 | "value": "File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "New", "onclick": "CreateNewDoc()"}, 7 | {"value": "Open", "onclick": "OpenDoc()"}, 8 | {"value": "Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} 12 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "50...100" 8 | status: 9 | project: 10 | default: 11 | target: 85% 12 | threshold: 0% 13 | patch: 14 | default: 15 | # basic 16 | target: 75% 17 | threshold: 10% 18 | -------------------------------------------------------------------------------- /examples/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #include "handler.h" 4 | 5 | #include 6 | 7 | int main(int argc, char** argv) 8 | { 9 | std::istringstream req("{\n \"user_id\": 10001\n}\n"); 10 | std::ostringstream resp; 11 | 12 | GetUserInfoHandler handler; 13 | handler.POST(req, resp); 14 | 15 | std::cout << "request: \n" << req.str() << std::endl; 16 | std::cout << "response: \n" << resp.str() << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/user_info.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #include "user_info.h" 4 | 5 | std::shared_ptr QueryUser(int user_id) 6 | { 7 | if (user_id != 10001) 8 | { 9 | return nullptr; 10 | } 11 | auto ptr = std::make_shared(UserInfo{ 12 | 10001, 13 | "John", 14 | { 15 | UserRole{ 100, { "READ" } }, 16 | UserRole{ 101, { "DELETE", "MODIFY" } }, 17 | }, 18 | }); 19 | return ptr; 20 | } 21 | -------------------------------------------------------------------------------- /tests/test_json/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #pragma once 4 | 5 | #include "ctype.h" 6 | 7 | #include 8 | #include 9 | 10 | using namespace configor; 11 | 12 | #define COMBINE(A, B) A##B 13 | #define WIDE(STR) COMBINE(L, STR) 14 | 15 | #define STR_ANY(ANY) #ANY 16 | #define STR(ANY) STR_ANY(ANY) 17 | 18 | #define RAW_STR "我是地球🌍" 19 | #define QUOTE_STR "\"我是地球🌍\"" 20 | #define ESCAPED_STR "\"\\u6211\\u662F\\u5730\\u7403\\uD83C\\uDF0D\"" 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{h,hpp,cpp}] 14 | charset = utf-8 15 | 16 | # 4 space indentation 17 | indent_style = space 18 | indent_size = 4 19 | 20 | # Matches the exact files 21 | [*.{json,xml}] 22 | indent_style = space 23 | indent_size = 2 24 | -------------------------------------------------------------------------------- /tests/data/json.org/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/data/json.org/3.json: -------------------------------------------------------------------------------- 1 | {"widget": { 2 | "debug": "on", 3 | "window": { 4 | "title": "Sample Konfabulator Widget", 5 | "name": "main_window", 6 | "width": 500, 7 | "height": 500 8 | }, 9 | "image": { 10 | "src": "Images/Sun.png", 11 | "name": "sun1", 12 | "hOffset": 250, 13 | "vOffset": 250, 14 | "alignment": "center" 15 | }, 16 | "text": { 17 | "data": "Click Here", 18 | "size": 36, 19 | "style": "bold", 20 | "name": "text1", 21 | "hOffset": 250, 22 | "vOffset": 100, 23 | "alignment": "center", 24 | "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 25 | } 26 | }} -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${CMAKE_CURRENT_LIST_DIR}/3rd-party) 2 | 3 | # Testing 4 | aux_source_directory(./test_basic_config BASIC_SRC) 5 | aux_source_directory(./test_json JSON_SRC) 6 | add_executable(${PROJECT_NAME}_test main.cpp ${BASIC_SRC} ${JSON_SRC}) 7 | 8 | add_test(NAME ${PROJECT_NAME}_test 9 | COMMAND ${PROJECT_NAME}_test 10 | WORKING_DIRECTORY ${PROJECT_ROOT_DIR} 11 | ) 12 | 13 | # Code Coverage Configuration 14 | option(ENABLE_COVERAGE "Enable coverage build." OFF) 15 | if(ENABLE_COVERAGE) 16 | message("Build with coverage infos.") 17 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) 18 | find_package(codecov) 19 | add_coverage(${PROJECT_NAME}_test) 20 | endif() 21 | -------------------------------------------------------------------------------- /examples/user_info.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #include 4 | #include 5 | 6 | using namespace configor; 7 | using std::string; 8 | using std::vector; 9 | 10 | // 用户角色 11 | struct UserRole 12 | { 13 | // 角色编号 14 | int code; 15 | // 权限列表 16 | vector permission_list; 17 | 18 | CONFIGOR_BIND(json::value, UserRole, REQUIRED(code), REQUIRED(permission_list)); 19 | }; 20 | 21 | // 用户信息 22 | struct UserInfo 23 | { 24 | // 用户id 25 | int user_id; 26 | // 用户名 27 | string user_name; 28 | // 角色列表 29 | vector role_list; 30 | 31 | CONFIGOR_BIND(json::value, UserInfo, REQUIRED(user_id), REQUIRED(user_name), REQUIRED(role_list)); 32 | }; 33 | 34 | extern std::shared_ptr QueryUser(int user_id); 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # vscode 35 | .vscode/ 36 | 37 | .DS_Store 38 | 39 | # cmake 40 | CMakeLists.txt.user 41 | CMakeCache.txt 42 | CMakeFiles 43 | CMakeScripts 44 | Testing/ 45 | Makefile 46 | cmake_install.cmake 47 | install_manifest.txt 48 | compile_commands.json 49 | CTestTestfile.cmake 50 | _deps 51 | .cmake/ 52 | 53 | # test files 54 | *_test 55 | build/ 56 | output/ 57 | 58 | # visual studio files 59 | .vs/ 60 | packages/ 61 | *.vcxproj.user 62 | 63 | .idea 64 | -------------------------------------------------------------------------------- /examples/handler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #include "user_info.h" 4 | 5 | #include 6 | #include 7 | 8 | struct Request 9 | { 10 | int user_id; 11 | 12 | CONFIGOR_BIND(json::value, Request, REQUIRED(user_id)); 13 | }; 14 | 15 | struct Response 16 | { 17 | std::shared_ptr user_info; 18 | 19 | CONFIGOR_BIND(json::value, Response, REQUIRED(user_info)); 20 | }; 21 | 22 | // 获取用户信息接口 23 | class GetUserInfoHandler 24 | { 25 | public: 26 | // POST请求 27 | void POST(std::istringstream& req, std::ostringstream& resp) 28 | { 29 | // 解析请求,可以直接反序列化到 Request 结构体中 30 | Request req_body; 31 | req >> json::wrap(req_body); 32 | 33 | // 读取用户信息 34 | auto user_info = QueryUser(req_body.user_id); 35 | 36 | // 响应请求,可以直接序列化到输出流中 37 | Response resp_body = { user_info }; 38 | resp << std::setw(4) << json::wrap(resp_body); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /tests/data/json.org/5.json: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "header": "SVG Viewer", 3 | "items": [ 4 | {"id": "Open"}, 5 | {"id": "OpenNew", "label": "Open New"}, 6 | null, 7 | {"id": "ZoomIn", "label": "Zoom In"}, 8 | {"id": "ZoomOut", "label": "Zoom Out"}, 9 | {"id": "OriginalView", "label": "Original View"}, 10 | null, 11 | {"id": "Quality"}, 12 | {"id": "Pause"}, 13 | {"id": "Mute"}, 14 | null, 15 | {"id": "Find", "label": "Find..."}, 16 | {"id": "FindAgain", "label": "Find Again"}, 17 | {"id": "Copy"}, 18 | {"id": "CopyAgain", "label": "Copy Again"}, 19 | {"id": "CopySVG", "label": "Copy SVG"}, 20 | {"id": "ViewSVG", "label": "View SVG"}, 21 | {"id": "ViewSource", "label": "View Source"}, 22 | {"id": "SaveAs", "label": "Save As"}, 23 | null, 24 | {"id": "Help"}, 25 | {"id": "About", "label": "About Adobe CVG Viewer..."} 26 | ] 27 | }} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Haibo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/3rd-party/fifo_map/LICENSE.MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2017 Niels Lohmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0 FATAL_ERROR) 2 | project(configor LANGUAGES CXX) 3 | 4 | # Use C++11 5 | set(CMAKE_CXX_STANDARD 11) 6 | # Require (at least) it 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # Don't use e.g. GNU extension (like -std=gnu++11) for portability 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | # Compiler args 11 | if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8 /W3 /WX") 13 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang) 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") 15 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") 17 | endif() 18 | # Root path 19 | set(PROJECT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) 20 | 21 | include_directories(${CMAKE_CURRENT_LIST_DIR}/include) 22 | 23 | add_subdirectory(examples examples) 24 | 25 | option (BUILD_TESTING "Build the testing tree." ON) 26 | # Only build tests if we are the top-level project 27 | # Allows this to be used by super projects with `add_subdirectory` 28 | if (BUILD_TESTING AND (PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)) 29 | include(CTest) 30 | enable_testing() 31 | add_subdirectory(tests tests) 32 | endif() 33 | -------------------------------------------------------------------------------- /cmake/llvm-cov-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This file is part of CMake-codecov. 4 | # 5 | # Copyright (c) 6 | # 2015-2020 RWTH Aachen University, Federal Republic of Germany 7 | # 8 | # See the LICENSE file in the package base directory for details 9 | # 10 | # Written by Alexander Haase, alexander.haase@rwth-aachen.de 11 | # 12 | 13 | if [ -z "$LLVM_COV_BIN" ] 14 | then 15 | echo "LLVM_COV_BIN not set!" >& 2 16 | exit 1 17 | fi 18 | 19 | 20 | # Get LLVM version to find out. 21 | LLVM_VERSION=$($LLVM_COV_BIN -version | grep -i "LLVM version" \ 22 | | sed "s/^\([A-Za-z ]*\)\([0-9]*\).\([0-9]*\).*$/\2.\3/g") 23 | 24 | if [ "$1" = "-v" ] 25 | then 26 | echo "llvm-cov-wrapper $LLVM_VERSION" 27 | exit 0 28 | fi 29 | 30 | 31 | if [ -n "$LLVM_VERSION" ] 32 | then 33 | MAJOR=$(echo $LLVM_VERSION | cut -d'.' -f1) 34 | MINOR=$(echo $LLVM_VERSION | cut -d'.' -f2) 35 | 36 | if [ $MAJOR -eq 3 ] && [ $MINOR -le 4 ] 37 | then 38 | if [ -f "$1" ] 39 | then 40 | filename=$(basename "$1") 41 | extension="${filename##*.}" 42 | 43 | case "$extension" in 44 | "gcno") exec $LLVM_COV_BIN --gcno="$1" ;; 45 | "gcda") exec $LLVM_COV_BIN --gcda="$1" ;; 46 | esac 47 | fi 48 | fi 49 | 50 | if [ $MAJOR -eq 3 ] && [ $MINOR -le 5 ] 51 | then 52 | exec $LLVM_COV_BIN $@ 53 | fi 54 | fi 55 | 56 | exec $LLVM_COV_BIN gcov $@ 57 | -------------------------------------------------------------------------------- /tests/3rd-party/catch2/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /include/configor/configor.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2020 configor - Nomango 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #pragma once 22 | #include "details/conversion.hpp" 23 | #include "details/parser.hpp" 24 | #include "details/serializer.hpp" 25 | #include "details/wrapper.hpp" 26 | 27 | #include // std::int64_t 28 | #include // std::map 29 | #include // std::string 30 | #include // std::vector 31 | 32 | namespace configor 33 | { 34 | 35 | struct value_tplargs 36 | { 37 | using boolean_type = bool; 38 | 39 | using integer_type = int64_t; 40 | 41 | using float_type = double; 42 | 43 | using char_type = char; 44 | 45 | template 46 | using string_type = std::basic_string<_CharTy, _Args...>; 47 | 48 | template 49 | using array_type = std::vector<_Kty, _Args...>; 50 | 51 | template 52 | using object_type = std::map<_Kty, _Ty, _Args...>; 53 | 54 | template 55 | using allocator_type = std::allocator<_Ty>; 56 | 57 | template 58 | using binder_type = value_binder<_Ty>; 59 | }; 60 | 61 | struct wvalue_tplargs : value_tplargs 62 | { 63 | using char_type = wchar_t; 64 | }; 65 | 66 | using value = basic_value; 67 | using wvalue = basic_value; 68 | 69 | } // namespace configor 70 | -------------------------------------------------------------------------------- /tests/test_json/test_unicode.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Nomango 2 | 3 | #include "common.h" 4 | 5 | #include // std::wstringstream 6 | 7 | TEST_CASE("test_unicode") 8 | { 9 | SECTION("test_dump_surrogate") 10 | { 11 | json::value j = RAW_STR; 12 | CHECK(json::dump(j) == QUOTE_STR); 13 | CHECK(json::dump(j, { json::serializer::with_unicode_escaping(false) }) == QUOTE_STR); 14 | CHECK(json::dump(j, { json::serializer::with_unicode_escaping(true) }) == ESCAPED_STR); 15 | 16 | wjson::value wj = WIDE(RAW_STR); 17 | CHECK(wjson::dump(wj) == WIDE(QUOTE_STR)); 18 | CHECK(wjson::dump(wj, { wjson::serializer::with_unicode_escaping(false) }) == WIDE(QUOTE_STR)); 19 | CHECK(wjson::dump(wj, { wjson::serializer::with_unicode_escaping(true) }) == WIDE(ESCAPED_STR)); 20 | } 21 | 22 | SECTION("test_ignore_encoding") 23 | { 24 | { 25 | json::value j; 26 | CHECK_NOTHROW(j = json::parse(QUOTE_STR, { json::parser::with_encoding() })); 27 | CHECK(j.get() == RAW_STR); 28 | } 29 | { 30 | json::value j = RAW_STR; 31 | CHECK(json::dump(j, { json::serializer::with_encoding() }) == QUOTE_STR); 32 | } 33 | } 34 | 35 | SECTION("test_parse_w") 36 | { 37 | auto j = wjson::parse(L"{ \"happy\": true, \"pi\": 3.141, \"name\": \"中文测试\" }"); 38 | CHECK(j[L"happy"].get()); 39 | CHECK(j[L"pi"].get() == Approx(3.141)); 40 | CHECK(j[L"name"].get() == L"中文测试"); 41 | } 42 | } 43 | 44 | class WCharTest 45 | { 46 | protected: 47 | WCharTest() 48 | { 49 | j = wjson::object{ 50 | { WIDE("pi"), 3.141 }, 51 | { WIDE("happy"), true }, 52 | { WIDE("name"), WIDE("Nomango") }, 53 | { WIDE("nothing"), nullptr }, 54 | { WIDE("answer"), wjson::object{ { WIDE("everything"), 42 } } }, 55 | { WIDE("list"), wjson::array{ 1, 0, 2 } }, 56 | { WIDE("object"), wjson::object{ { WIDE("currency"), WIDE("USD") }, { WIDE("value"), 42.99 } } }, 57 | }; 58 | } 59 | 60 | wjson::value j; 61 | }; 62 | 63 | TEST_CASE_METHOD(WCharTest, "test_write_to_stream_w") 64 | { 65 | std::wstringstream ss; 66 | ss << wjson::wrap(j); 67 | CHECK(ss.str() == wjson::dump(j)); 68 | 69 | ss.str(L""); 70 | ss << std::setw(4) << wjson::wrap(j); 71 | CHECK(ss.str() == wjson::dump(j, { wjson::serializer::with_indent(4) })); 72 | 73 | ss.str(L""); 74 | ss << std::setw(2) << std::setfill(L'.') << wjson::wrap(j); 75 | CHECK(ss.str() == wjson::dump(j, { wjson::serializer::with_indent(2, L'.') })); 76 | } 77 | -------------------------------------------------------------------------------- /include/configor/details/token.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2020 configor - Nomango 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #pragma once 22 | 23 | namespace configor 24 | { 25 | 26 | enum class token_type 27 | { 28 | uninitialized, 29 | 30 | literal_true, 31 | literal_false, 32 | literal_null, 33 | 34 | value_string, 35 | value_integer, 36 | value_float, 37 | 38 | begin_array, 39 | end_array, 40 | 41 | begin_object, 42 | end_object, 43 | 44 | name_separator, 45 | value_separator, 46 | 47 | end_of_input 48 | }; 49 | 50 | inline const char* to_string(token_type token) 51 | { 52 | switch (token) 53 | { 54 | case token_type::uninitialized: 55 | return "uninitialized"; 56 | case token_type::literal_true: 57 | return "literal_true"; 58 | case token_type::literal_false: 59 | return "literal_false"; 60 | case token_type::literal_null: 61 | return "literal_null"; 62 | case token_type::value_string: 63 | return "value_string"; 64 | case token_type::value_integer: 65 | return "value_integer"; 66 | case token_type::value_float: 67 | return "value_float"; 68 | case token_type::begin_array: 69 | return "begin_array"; 70 | case token_type::end_array: 71 | return "end_array"; 72 | case token_type::begin_object: 73 | return "begin_object"; 74 | case token_type::end_object: 75 | return "end_object"; 76 | case token_type::name_separator: 77 | return "name_separator"; 78 | case token_type::value_separator: 79 | return "value_separator"; 80 | case token_type::end_of_input: 81 | return "end_of_input"; 82 | } 83 | return "unknown"; 84 | } 85 | 86 | } // namespace configor 87 | -------------------------------------------------------------------------------- /README-zh.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![logo](./assets/logo.png) 4 | 5 | 6 | [![Open in VSCode](https://img.shields.io/badge/open-in%20Visual%20Studio%20Code-blue)](https://open.vscode.dev/Nomango/configor) 7 | [![Github status](https://github.com/Nomango/configor/actions/workflows/unit_tests.yml/badge.svg?branch=master)](https://github.com/Nomango/configor/actions) 8 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cf98f6b174fe4dd19f1e4574ac527a07)](https://www.codacy.com/gh/Nomango/configor/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Nomango/configor&utm_campaign=Badge_Grade) 9 | [![codecov](https://codecov.io/gh/Nomango/configor/branch/master/graph/badge.svg?token=OO71U89I5N)](https://codecov.io/gh/Nomango/configor) 10 | [![GitHub release](https://img.shields.io/github/release/nomango/configor)](https://github.com/Nomango/configor/releases/latest) 11 | [![GitHub license](https://img.shields.io/github/license/nomango/configor)](https://github.com/Nomango/configor/blob/master/LICENSE) 12 | 13 | 为 C++11 设计的轻量级配置库 14 | 15 | [EN](./README.md) | [中文](./README-zh.md) 16 | 17 |
18 | 19 | ## 特点 20 | 21 | - 仅头文件,低接入成本 22 | - STL-like,低学习成本 23 | - 自定义类型转换与序列化 24 | - 完备的 Unicode 支持 25 | - ASCII & 宽字符支持 26 | 27 | ## 快速上手 28 | 29 | 创建 JSON 文档对象 30 | 31 | ```cpp 32 | json::value j; 33 | j["integer"] = 1; 34 | j["float"] = 1.5; 35 | j["string"] = "something"; 36 | j["boolean"] = true; 37 | j["user"]["id"] = 10; 38 | j["user"]["name"] = "Nomango"; 39 | 40 | json::value j2 = json::object{ 41 | { "null", nullptr }, 42 | { "integer", 1 }, 43 | { "float", 1.3 }, 44 | { "boolean", true }, 45 | { "string", "something" }, 46 | { "array", json::array{ 1, 2 } }, 47 | { "object", json::object{ 48 | { "key", "value" }, 49 | { "key2", "value2" }, 50 | }}, 51 | }; 52 | ``` 53 | 54 | 类型转换 & 序列化: 55 | 56 | ```cpp 57 | struct User 58 | { 59 | std::string name; 60 | int age; 61 | 62 | // 将自定义类型绑定到 configor 63 | CONFIGOR_BIND(json::value, User, REQUIRED(name), OPTIONAL(age)) 64 | }; 65 | 66 | // User -> json 67 | json::value j = User{"John", 18}; 68 | // json -> User 69 | User u = json::object{{"name", "John"}, {"age", 18}}; 70 | 71 | // User -> string 72 | std::string str = json::dump(User{"John", 18}); 73 | // string -> User 74 | User u = json::parse("{\"name\": \"John\", \"age\": 18}"); 75 | 76 | // User -> stream 77 | std::cout << json::wrap(User{"John", 18}); 78 | // stream -> User 79 | User u; 80 | std::cin >> json::wrap(u); 81 | ``` 82 | 83 | 更多内容请到 [wiki](https://github.com/Nomango/configor/wiki) 查看。 84 | 85 | ## Star History 86 | 87 | [![Star History Chart](https://api.star-history.com/svg?repos=nomango/configor&type=Date)](https://star-history.com/#nomango/configor&Date) 88 | 89 | ## 计划 90 | 91 | - [x] 自定义类型转换 92 | - [x] Unicode 支持 93 | - [x] 单元测试覆盖率达到 85% 94 | - [ ] 完善错误信息 95 | - [ ] YAML 支持 96 | - [ ] ini 支持 97 | - [ ] json5 支持 98 | - [ ] SAX 工具 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![logo](./assets/logo.png) 4 | 5 | 6 | [![Open in VSCode](https://img.shields.io/badge/open-in%20Visual%20Studio%20Code-blue)](https://open.vscode.dev/Nomango/configor) 7 | [![Github status](https://github.com/Nomango/configor/actions/workflows/unit_tests.yml/badge.svg?branch=master)](https://github.com/Nomango/configor/actions) 8 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cf98f6b174fe4dd19f1e4574ac527a07)](https://www.codacy.com/gh/Nomango/configor/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Nomango/configor&utm_campaign=Badge_Grade) 9 | [![codecov](https://codecov.io/gh/Nomango/configor/branch/master/graph/badge.svg?token=OO71U89I5N)](https://codecov.io/gh/Nomango/configor) 10 | [![GitHub release](https://img.shields.io/github/release/nomango/configor)](https://github.com/Nomango/configor/releases/latest) 11 | [![GitHub license](https://img.shields.io/github/license/nomango/configor)](https://github.com/Nomango/configor/blob/master/LICENSE) 12 | 13 | A light weight configuration library for C++11. 14 | 15 | [EN](./README.md) | [中文](./README-zh.md) 16 | 17 |
18 | 19 | ## Features 20 | 21 | - Header-only & STL-like 22 | - Custom type conversion & serialization 23 | - Complete Unicode support 24 | - ASCII & Wide-character support 25 | 26 | ## Quick start 27 | 28 | Create JSON objects: 29 | 30 | ```cpp 31 | json::value j; 32 | j["integer"] = 1; 33 | j["float"] = 1.5; 34 | j["string"] = "something"; 35 | j["boolean"] = true; 36 | j["user"]["id"] = 10; 37 | j["user"]["name"] = "Nomango"; 38 | 39 | json::value j2 = json::object{ 40 | { "null", nullptr }, 41 | { "integer", 1 }, 42 | { "float", 1.3 }, 43 | { "boolean", true }, 44 | { "string", "something" }, 45 | { "array", json::array{ 1, 2 } }, 46 | { "object", json::object{ 47 | { "key", "value" }, 48 | { "key2", "value2" }, 49 | }}, 50 | }; 51 | ``` 52 | 53 | Conversion & Serialization: 54 | 55 | ```cpp 56 | struct User 57 | { 58 | std::string name; 59 | int age; 60 | 61 | // bind custom type to configor 62 | CONFIGOR_BIND(json::value, User, REQUIRED(name), OPTIONAL(age)) 63 | }; 64 | 65 | // User -> json 66 | json::value j = User{"John", 18}; 67 | // json -> User 68 | User u = json::object{{"name", "John"}, {"age", 18}}; 69 | 70 | // User -> string 71 | std::string str = json::dump(User{"John", 18}); 72 | // string -> User 73 | User u = json::parse("{\"name\": \"John\", \"age\": 18}"); 74 | 75 | // User -> stream 76 | std::cout << json::wrap(User{"John", 18}); 77 | // stream -> User 78 | User u; 79 | std::cin >> json::wrap(u); 80 | ``` 81 | 82 | Learn more from the [wiki](https://github.com/Nomango/configor/wiki). 83 | 84 | ## Star History 85 | 86 | [![Star History Chart](https://api.star-history.com/svg?repos=nomango/configor&type=Date)](https://star-history.com/#nomango/configor&Date) 87 | 88 | ## Plan 89 | 90 | - [x] Custom type conversion 91 | - [x] Unicode support 92 | - [x] Unit test coverage above 85% 93 | - [ ] Improve error message 94 | - [ ] YAML support 95 | - [ ] ini support 96 | - [ ] json5 support 97 | - [ ] SAX tool 98 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Clang-format version v9.0.0 2 | --- 3 | Language: Cpp 4 | BasedOnStyle: Google 5 | 6 | ColumnLimit: 120 7 | 8 | ## 9 | ## Indent Style 10 | ## 11 | 12 | IndentWidth: 4 13 | AccessModifierOffset: -4 14 | ConstructorInitializerIndentWidth: 4 15 | ContinuationIndentWidth: 4 16 | TabWidth: 4 17 | UseTab: Never 18 | IndentCaseLabels: false 19 | NamespaceIndentation: None 20 | 21 | ## 22 | ## Align Style 23 | ## 24 | 25 | AlignAfterOpenBracket: Align 26 | AlignConsecutiveAssignments: true 27 | AlignConsecutiveDeclarations: true 28 | AlignEscapedNewlinesLeft: true 29 | AlignOperands: true 30 | AlignTrailingComments: true 31 | PointerAlignment: Left 32 | 33 | ## 34 | ## SingleLine Style 35 | ## 36 | 37 | AllowAllParametersOfDeclarationOnNextLine: true 38 | AllowShortBlocksOnASingleLine: false 39 | AllowShortCaseLabelsOnASingleLine: false 40 | AllowShortFunctionsOnASingleLine: Empty 41 | AllowShortIfStatementsOnASingleLine: false 42 | AllowShortLoopsOnASingleLine: false 43 | AlwaysBreakAfterDefinitionReturnType: None 44 | AlwaysBreakAfterReturnType: None 45 | AlwaysBreakBeforeMultilineStrings: false 46 | AlwaysBreakTemplateDeclarations: true 47 | BinPackArguments: true 48 | BinPackParameters: true 49 | BreakBeforeBraces: Allman 50 | BraceWrapping: 51 | AfterClass: true 52 | AfterControlStatement: true 53 | AfterEnum: true 54 | AfterFunction: true 55 | AfterNamespace: true 56 | AfterObjCDeclaration: true 57 | AfterStruct: true 58 | AfterUnion: true 59 | BeforeCatch: true 60 | BeforeElse: true 61 | IndentBraces: true 62 | BreakBeforeBinaryOperators: NonAssignment 63 | BreakBeforeTernaryOperators: true 64 | CommentPragmas: "^ IWYU pragma:" 65 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 66 | 67 | ## 68 | ## Others 69 | ## 70 | 71 | BreakConstructorInitializers: BeforeComma 72 | BreakInheritanceList: BeforeComma 73 | ReflowComments: true 74 | SortIncludes: true 75 | Cpp11BracedListStyle: false 76 | DerivePointerAlignment: false 77 | DisableFormat: false 78 | ExperimentalAutoDetectBinPacking: false 79 | ForEachMacros: [foreach, Q_FOREACH, BOOST_FOREACH] 80 | IncludeCategories: 81 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 82 | Priority: 2 83 | SortPriority: 2 84 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 85 | Priority: 3 86 | - Regex: '<[[:alnum:].]+>' 87 | Priority: 4 88 | - Regex: '.*' 89 | Priority: 1 90 | SortPriority: 0 91 | IndentWrappedFunctionNames: false 92 | KeepEmptyLinesAtTheStartOfBlocks: true 93 | MacroBlockBegin: "" 94 | MacroBlockEnd: "" 95 | MaxEmptyLinesToKeep: 1 96 | PenaltyBreakBeforeFirstCallParameter: 19 97 | PenaltyBreakComment: 300 98 | PenaltyBreakFirstLessLess: 120 99 | PenaltyBreakString: 1000 100 | PenaltyExcessCharacter: 1000000 101 | PenaltyReturnTypeOnItsOwnLine: 60 102 | SpaceAfterCStyleCast: false 103 | SpaceBeforeAssignmentOperators: true 104 | SpaceBeforeParens: ControlStatements 105 | SpaceInEmptyParentheses: false 106 | SpacesBeforeTrailingComments: 2 107 | SpacesInAngles: false 108 | SpacesInContainerLiterals: true 109 | SpacesInCStyleCastParentheses: false 110 | SpacesInParentheses: false 111 | SpacesInSquareBrackets: false 112 | Standard: Cpp11 113 | -------------------------------------------------------------------------------- /tests/data/json.org/4.json: -------------------------------------------------------------------------------- 1 | {"web-app": { 2 | "servlet": [ 3 | { 4 | "servlet-name": "cofaxCDS", 5 | "servlet-class": "org.cofax.cds.CDSServlet", 6 | "init-param": { 7 | "configGlossary:installationAt": "Philadelphia, PA", 8 | "configGlossary:adminEmail": "ksm@pobox.com", 9 | "configGlossary:poweredBy": "Cofax", 10 | "configGlossary:poweredByIcon": "/images/cofax.gif", 11 | "configGlossary:staticPath": "/content/static", 12 | "templateProcessorClass": "org.cofax.WysiwygTemplate", 13 | "templateLoaderClass": "org.cofax.FilesTemplateLoader", 14 | "templatePath": "templates", 15 | "templateOverridePath": "", 16 | "defaultListTemplate": "listTemplate.htm", 17 | "defaultFileTemplate": "articleTemplate.htm", 18 | "useJSP": false, 19 | "jspListTemplate": "listTemplate.jsp", 20 | "jspFileTemplate": "articleTemplate.jsp", 21 | "cachePackageTagsTrack": 200, 22 | "cachePackageTagsStore": 200, 23 | "cachePackageTagsRefresh": 60, 24 | "cacheTemplatesTrack": 100, 25 | "cacheTemplatesStore": 50, 26 | "cacheTemplatesRefresh": 15, 27 | "cachePagesTrack": 200, 28 | "cachePagesStore": 100, 29 | "cachePagesRefresh": 10, 30 | "cachePagesDirtyRead": 10, 31 | "searchEngineListTemplate": "forSearchEnginesList.htm", 32 | "searchEngineFileTemplate": "forSearchEngines.htm", 33 | "searchEngineRobotsDb": "WEB-INF/robots.db", 34 | "useDataStore": true, 35 | "dataStoreClass": "org.cofax.SqlDataStore", 36 | "redirectionClass": "org.cofax.SqlRedirection", 37 | "dataStoreName": "cofax", 38 | "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", 39 | "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", 40 | "dataStoreUser": "sa", 41 | "dataStorePassword": "dataStoreTestQuery", 42 | "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", 43 | "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", 44 | "dataStoreInitConns": 10, 45 | "dataStoreMaxConns": 100, 46 | "dataStoreConnUsageLimit": 100, 47 | "dataStoreLogLevel": "debug", 48 | "maxUrlLength": 500}}, 49 | { 50 | "servlet-name": "cofaxEmail", 51 | "servlet-class": "org.cofax.cds.EmailServlet", 52 | "init-param": { 53 | "mailHost": "mail1", 54 | "mailHostOverride": "mail2"}}, 55 | { 56 | "servlet-name": "cofaxAdmin", 57 | "servlet-class": "org.cofax.cds.AdminServlet"}, 58 | 59 | { 60 | "servlet-name": "fileServlet", 61 | "servlet-class": "org.cofax.cds.FileServlet"}, 62 | { 63 | "servlet-name": "cofaxTools", 64 | "servlet-class": "org.cofax.cms.CofaxToolsServlet", 65 | "init-param": { 66 | "templatePath": "toolstemplates/", 67 | "log": 1, 68 | "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", 69 | "logMaxSize": "", 70 | "dataLog": 1, 71 | "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", 72 | "dataLogMaxSize": "", 73 | "removePageCache": "/content/admin/remove?cache=pages&id=", 74 | "removeTemplateCache": "/content/admin/remove?cache=templates&id=", 75 | "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", 76 | "lookInContext": 1, 77 | "adminGroupID": 4, 78 | "betaServer": true}}], 79 | "servlet-mapping": { 80 | "cofaxCDS": "/", 81 | "cofaxEmail": "/cofaxutil/aemail/*", 82 | "cofaxAdmin": "/admin/*", 83 | "fileServlet": "/static/*", 84 | "cofaxTools": "/tools/*"}, 85 | 86 | "taglib": { 87 | "taglib-uri": "cofax.tld", 88 | "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} -------------------------------------------------------------------------------- /include/configor/details/exception.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2020 configor - Nomango 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #pragma once 22 | #include // std::runtime_error, std::exception_ptr, std::rethrow_exception 23 | #include // std::string 24 | 25 | #ifndef CONFIGOR_ASSERT 26 | #include // assert 27 | #define CONFIGOR_ASSERT(...) assert(__VA_ARGS__) 28 | #endif 29 | 30 | namespace configor 31 | { 32 | 33 | // 34 | // exceptions 35 | // 36 | 37 | class configor_exception : public std::runtime_error 38 | { 39 | public: 40 | explicit configor_exception(const char* message) 41 | : std::runtime_error(message) 42 | { 43 | } 44 | 45 | explicit configor_exception(const std::string& message) 46 | : std::runtime_error(message) 47 | { 48 | } 49 | }; 50 | 51 | class configor_type_error : public configor_exception 52 | { 53 | public: 54 | explicit configor_type_error(const std::string& message) 55 | : configor_exception("value type error: " + message) 56 | { 57 | } 58 | }; 59 | 60 | class configor_invalid_key : public configor_exception 61 | { 62 | public: 63 | explicit configor_invalid_key(const std::string& message) 64 | : configor_exception("invalid value key error: " + message) 65 | { 66 | } 67 | }; 68 | 69 | class configor_invalid_iterator : public configor_exception 70 | { 71 | public: 72 | explicit configor_invalid_iterator(const std::string& message) 73 | : configor_exception("invalid value iterator error: " + message) 74 | { 75 | } 76 | }; 77 | 78 | class configor_deserialization_error : public configor_exception 79 | { 80 | public: 81 | explicit configor_deserialization_error(const std::string& message) 82 | : configor_exception("value deserialization error: " + message) 83 | { 84 | } 85 | }; 86 | 87 | class configor_serialization_error : public configor_exception 88 | { 89 | public: 90 | explicit configor_serialization_error(const std::string& message) 91 | : configor_exception("value serialization error: " + message) 92 | { 93 | } 94 | }; 95 | 96 | // 97 | // error handler 98 | // 99 | 100 | enum class error_policy 101 | { 102 | strict = 1, // throw exceptions 103 | record = 2, // record error message 104 | ignore = 3, // ignore all errors 105 | }; 106 | 107 | class error_handler 108 | { 109 | public: 110 | virtual void handle(std::exception_ptr eptr) = 0; 111 | }; 112 | 113 | template 114 | class error_handler_with; 115 | 116 | template <> 117 | class error_handler_with : public error_handler 118 | { 119 | public: 120 | virtual void handle(std::exception_ptr eptr) override 121 | { 122 | std::rethrow_exception(eptr); 123 | } 124 | }; 125 | 126 | template <> 127 | class error_handler_with : public error_handler 128 | { 129 | public: 130 | virtual void handle(std::exception_ptr eptr) override 131 | { 132 | // DO NOTHING 133 | } 134 | }; 135 | 136 | template <> 137 | class error_handler_with : public error_handler 138 | { 139 | public: 140 | virtual void handle(std::exception_ptr eptr) override 141 | { 142 | try 143 | { 144 | if (eptr) 145 | { 146 | std::rethrow_exception(eptr); 147 | } 148 | } 149 | catch (const configor_exception& e) 150 | { 151 | this->error = e.what(); 152 | } 153 | } 154 | 155 | std::string error; 156 | }; 157 | 158 | } // namespace configor 159 | -------------------------------------------------------------------------------- /cmake/FindGcov.cmake: -------------------------------------------------------------------------------- 1 | # This file is part of CMake-codecov. 2 | # 3 | # Copyright (c) 4 | # 2015-2020 RWTH Aachen University, Federal Republic of Germany 5 | # 6 | # See the LICENSE file in the package base directory for details 7 | # 8 | # Written by Alexander Haase, alexander.haase@rwth-aachen.de 9 | # 10 | 11 | 12 | # include required Modules 13 | include(FindPackageHandleStandardArgs) 14 | 15 | 16 | # Search for gcov binary. 17 | set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) 18 | set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) 19 | 20 | get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) 21 | foreach (LANG ${ENABLED_LANGUAGES}) 22 | # Gcov evaluation is dependent on the used compiler. Check gcov support for 23 | # each compiler that is used. If gcov binary was already found for this 24 | # compiler, do not try to find it again. 25 | if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) 26 | get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) 27 | 28 | if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") 29 | # Some distributions like OSX (homebrew) ship gcov with the compiler 30 | # version appended as gcov-x. To find this binary we'll build the 31 | # suggested binary name with the compiler version. 32 | string(REGEX MATCH "^[0-9]+" GCC_VERSION 33 | "${CMAKE_${LANG}_COMPILER_VERSION}") 34 | 35 | find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov 36 | HINTS ${COMPILER_PATH}) 37 | 38 | elseif ("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "^(Apple)?Clang$") 39 | # Some distributions like Debian ship llvm-cov with the compiler 40 | # version appended as llvm-cov-x.y. To find this binary we'll build 41 | # the suggested binary name with the compiler version. 42 | string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION 43 | "${CMAKE_${LANG}_COMPILER_VERSION}") 44 | 45 | # llvm-cov prior version 3.5 seems to be not working with coverage 46 | # evaluation tools, but these versions are compatible with the gcc 47 | # gcov tool. 48 | if(LLVM_VERSION VERSION_GREATER 3.4) 49 | find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" 50 | "llvm-cov" HINTS ${COMPILER_PATH}) 51 | mark_as_advanced(LLVM_COV_BIN) 52 | 53 | if (LLVM_COV_BIN) 54 | find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS 55 | ${CMAKE_MODULE_PATH}) 56 | if (LLVM_COV_WRAPPER) 57 | set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") 58 | 59 | # set additional parameters 60 | set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV 61 | "LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING 62 | "Environment variables for llvm-cov-wrapper.") 63 | mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) 64 | endif () 65 | endif () 66 | endif () 67 | 68 | if (NOT GCOV_BIN) 69 | # Fall back to gcov binary if llvm-cov was not found or is 70 | # incompatible. This is the default on OSX, but may crash on 71 | # recent Linux versions. 72 | find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) 73 | endif () 74 | endif () 75 | 76 | 77 | if (GCOV_BIN) 78 | set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING 79 | "${LANG} gcov binary.") 80 | 81 | if (NOT CMAKE_REQUIRED_QUIET) 82 | message("-- Found gcov evaluation for " 83 | "${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") 84 | endif() 85 | 86 | unset(GCOV_BIN CACHE) 87 | endif () 88 | endif () 89 | endforeach () 90 | 91 | 92 | 93 | 94 | # Add a new global target for all gcov targets. This target could be used to 95 | # generate the gcov files for the whole project instead of calling -gcov 96 | # for each target. 97 | if (NOT TARGET gcov) 98 | add_custom_target(gcov) 99 | endif (NOT TARGET gcov) 100 | 101 | 102 | 103 | # This function will add gcov evaluation for target . Only sources of 104 | # this target will be evaluated and no dependencies will be added. It will call 105 | # Gcov on any source file of once and store the gcov file in the same 106 | # directory. 107 | function (add_gcov_target TNAME) 108 | get_target_property(TBIN_DIR ${TNAME} BINARY_DIR) 109 | set(TDIR ${TBIN_DIR}/CMakeFiles/${TNAME}.dir) 110 | 111 | # We don't have to check, if the target has support for coverage, thus this 112 | # will be checked by add_coverage_target in Findcoverage.cmake. Instead we 113 | # have to determine which gcov binary to use. 114 | get_target_property(TSOURCES ${TNAME} SOURCES) 115 | set(SOURCES "") 116 | set(TCOMPILER "") 117 | foreach (FILE ${TSOURCES}) 118 | codecov_path_of_source(${FILE} FILE) 119 | if (NOT "${FILE}" STREQUAL "") 120 | codecov_lang_of_source(${FILE} LANG) 121 | if (NOT "${LANG}" STREQUAL "") 122 | list(APPEND SOURCES "${FILE}") 123 | set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) 124 | endif () 125 | endif () 126 | endforeach () 127 | 128 | # If no gcov binary was found, coverage data can't be evaluated. 129 | if (NOT GCOV_${TCOMPILER}_BIN) 130 | message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") 131 | return() 132 | endif () 133 | 134 | set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") 135 | set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") 136 | 137 | 138 | set(BUFFER "") 139 | set(NULL_DEVICE "/dev/null") 140 | if(WIN32) 141 | set(NULL_DEVICE "NUL") 142 | endif() 143 | foreach(FILE ${SOURCES}) 144 | get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) 145 | 146 | # call gcov 147 | add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov 148 | COMMAND ${GCOV_ENV} ${GCOV_BIN} -p ${TDIR}/${FILE}.gcno > ${NULL_DEVICE} 149 | DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno 150 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 151 | ) 152 | 153 | list(APPEND BUFFER ${TDIR}/${FILE}.gcov) 154 | endforeach() 155 | 156 | 157 | # add target for gcov evaluation of 158 | add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) 159 | 160 | # add evaluation target to the global gcov target. 161 | add_dependencies(gcov ${TNAME}-gcov) 162 | endfunction (add_gcov_target) 163 | -------------------------------------------------------------------------------- /include/configor/details/wrapper.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2021 configor - Nomango 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #pragma once 22 | #include "parser.hpp" 23 | #include "serializer.hpp" 24 | 25 | namespace configor 26 | { 27 | 28 | namespace detail 29 | { 30 | template 31 | class ostream_wrapper 32 | { 33 | public: 34 | using config_type = _ConfigTy; 35 | using value_type = typename _ConfigTy::value; 36 | 37 | explicit ostream_wrapper(const _Ty& v) 38 | : v_(v) 39 | { 40 | } 41 | 42 | template 43 | friend std::basic_ostream<_TargetCharTy, _Traits>& operator<<(std::basic_ostream<_TargetCharTy, _Traits>& out, 44 | const ostream_wrapper& wrapper) 45 | { 46 | typename std::basic_ostream<_TargetCharTy, _Traits>::sentry s(out); 47 | if (s) 48 | { 49 | config_type::dump(out, static_cast(wrapper.v_)); 50 | } 51 | return out; 52 | } 53 | 54 | private: 55 | const _Ty& v_; 56 | }; 57 | 58 | template 59 | class ostream_wrapper<_ConfigTy, basic_value<_Args>> 60 | { 61 | public: 62 | using config_type = _ConfigTy; 63 | using value_type = typename _ConfigTy::value; 64 | 65 | explicit ostream_wrapper(const value_type& v) 66 | : v_(v) 67 | { 68 | } 69 | 70 | template 71 | friend std::basic_ostream<_TargetCharTy, _Traits>& operator<<(std::basic_ostream<_TargetCharTy, _Traits>& out, 72 | const ostream_wrapper& wrapper) 73 | { 74 | typename std::basic_ostream<_TargetCharTy, _Traits>::sentry s(out); 75 | if (s) 76 | { 77 | config_type::dump(out, wrapper.v_); 78 | } 79 | return out; 80 | } 81 | 82 | private: 83 | const value_type& v_; 84 | }; 85 | 86 | template 87 | class iostream_wrapper : public ostream_wrapper<_ConfigTy, _Ty> 88 | { 89 | public: 90 | using config_type = _ConfigTy; 91 | using value_type = typename _ConfigTy::value; 92 | 93 | explicit iostream_wrapper(_Ty& v) 94 | : ostream_wrapper<_ConfigTy, _Ty>(v) 95 | , v_(v) 96 | { 97 | } 98 | 99 | template 100 | friend std::basic_istream<_SourceCharTy, _Traits>& 101 | operator>>(std::basic_istream<_SourceCharTy, _Traits>& in, 102 | const iostream_wrapper& wrapper /* wrapper must be lvalue */) 103 | { 104 | typename std::basic_istream<_SourceCharTy, _Traits>::sentry s(in); 105 | if (s) 106 | { 107 | value_type c{}; 108 | config_type::parse(c, in); 109 | const_cast<_Ty&>(wrapper.v_) = c.template get<_Ty>(); 110 | } 111 | return in; 112 | } 113 | 114 | private: 115 | _Ty& v_; 116 | }; 117 | 118 | template 119 | class iostream_wrapper<_ConfigTy, basic_value<_Args>> : public ostream_wrapper<_ConfigTy, basic_value<_Args>> 120 | { 121 | public: 122 | using config_type = _ConfigTy; 123 | using value_type = typename _ConfigTy::value; 124 | 125 | explicit iostream_wrapper(value_type& v) 126 | : ostream_wrapper<_ConfigTy, value_type>(v) 127 | , v_(v) 128 | { 129 | } 130 | 131 | template 132 | friend std::basic_istream<_SourceCharTy, _Traits>& 133 | operator>>(std::basic_istream<_SourceCharTy, _Traits>& in, 134 | const iostream_wrapper& wrapper /* wrapper must be lvalue */) 135 | { 136 | typename std::basic_istream<_SourceCharTy, _Traits>::sentry s(in); 137 | if (s) 138 | { 139 | config_type::parse(const_cast(wrapper.v_), in); 140 | } 141 | return in; 142 | } 143 | 144 | private: 145 | value_type& v_; 146 | }; 147 | 148 | template 149 | class iostream_wrapper_maker 150 | { 151 | public: 152 | using config_type = _ConfigTy; 153 | using value_type = _ValTy; 154 | 155 | template ::value 156 | || has_to_value::value>::type> 157 | static inline ostream_wrapper wrap(const _Ty& v) 158 | { 159 | return ostream_wrapper(v); 160 | } 161 | 162 | template ::value 163 | || is_value_getable::value) 164 | && !std::is_pointer<_Ty>::value>::type> 165 | static inline iostream_wrapper wrap(_Ty& v) 166 | { 167 | return iostream_wrapper(v); 168 | } 169 | }; 170 | } // namespace detail 171 | 172 | } // namespace configor 173 | -------------------------------------------------------------------------------- /include/configor/details/declare.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2021 configor - Nomango 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | #pragma once 22 | #include // std::false_type, std::true_type, std::remove_cv, std::remove_reference 23 | 24 | namespace configor 25 | { 26 | 27 | // 28 | // forward declare 29 | // 30 | 31 | template 32 | class value_binder; 33 | 34 | template 35 | class basic_value; 36 | 37 | // 38 | // is_value 39 | // 40 | 41 | template 42 | struct is_value : std::false_type 43 | { 44 | }; 45 | 46 | template 47 | struct is_value> : std::true_type 48 | { 49 | }; 50 | 51 | // 52 | // value_constant 53 | // 54 | 55 | struct value_constant 56 | { 57 | enum type 58 | { 59 | null, 60 | integer, 61 | floating, 62 | string, 63 | array, 64 | object, 65 | boolean, 66 | }; 67 | }; 68 | 69 | inline const char* to_string(value_constant::type t) noexcept 70 | { 71 | switch (t) 72 | { 73 | case value_constant::type::object: 74 | return "object"; 75 | case value_constant::type::array: 76 | return "array"; 77 | case value_constant::type::string: 78 | return "string"; 79 | case value_constant::type::integer: 80 | return "integer"; 81 | case value_constant::type::floating: 82 | return "float"; 83 | case value_constant::type::boolean: 84 | return "boolean"; 85 | case value_constant::type::null: 86 | return "null"; 87 | } 88 | return "unknown"; 89 | } 90 | 91 | namespace detail 92 | { 93 | 94 | // priority 95 | 96 | template 97 | struct priority : priority

98 | { 99 | }; 100 | 101 | template <> 102 | struct priority<0> 103 | { 104 | }; 105 | 106 | // remove_cvref 107 | 108 | template 109 | struct remove_cvref 110 | { 111 | using type = typename std::remove_cv::type>::type; 112 | }; 113 | 114 | // always_void 115 | 116 | template 117 | struct always_void 118 | { 119 | using type = void; 120 | }; 121 | 122 | // exact_detect 123 | 124 | template class _Op, class... _Args> 125 | struct detect_impl 126 | { 127 | struct dummy 128 | { 129 | dummy() = delete; 130 | ~dummy() = delete; 131 | dummy(const dummy&) = delete; 132 | }; 133 | 134 | using type = dummy; 135 | 136 | static constexpr bool value = false; 137 | }; 138 | 139 | template