From e56bdacdec645e49415c139a4a518a9d27cbb39d Mon Sep 17 00:00:00 2001 From: qicosmos Date: Sun, 18 Apr 2021 11:07:01 +0800 Subject: [PATCH] clang-format11 format code. --- example/example.vcxproj | 2 +- example/main.cpp | 450 +- include/cinatra.hpp | 4 +- include/cinatra/async_client.hpp | 907 +- include/cinatra/client_factory.hpp | 105 +- include/cinatra/connection.hpp | 51 +- include/cinatra/cookie.hpp | 253 +- include/cinatra/define.h | 55 +- include/cinatra/dh1024.pem | 11 +- include/cinatra/function_traits.hpp | 146 +- include/cinatra/gzip.hpp | 248 +- include/cinatra/http_cache.hpp | 184 +- include/cinatra/http_client.hpp | 2059 +- include/cinatra/http_parser.hpp | 221 +- include/cinatra/http_router.hpp | 446 +- include/cinatra/http_server.hpp | 24 +- include/cinatra/io_service_pool.hpp | 200 +- include/cinatra/itoa.hpp | 457 +- include/cinatra/itoa_jeaiii.hpp | 144 +- include/cinatra/mime_types.hpp | 1004 +- include/cinatra/modern_callback.h | 93 +- include/cinatra/multipart_parser.hpp | 857 +- include/cinatra/multipart_reader.hpp | 246 +- include/cinatra/nlohmann_json.hpp | 38011 ++++++++++++------------ include/cinatra/picohttpparser.h | 1085 +- include/cinatra/render.h | 1481 +- include/cinatra/request.hpp | 24 +- include/cinatra/response.hpp | 20 +- include/cinatra/response_cv.hpp | 778 +- include/cinatra/response_parser.hpp | 429 +- include/cinatra/router.hpp | 133 +- include/cinatra/server.crt | 34 +- include/cinatra/server.key | 37 +- include/cinatra/session.hpp | 157 +- include/cinatra/session_manager.hpp | 138 +- include/cinatra/sha1.hpp | 451 +- include/cinatra/upload_file.hpp | 178 +- include/cinatra/uri.hpp | 542 +- include/cinatra/url_encode_decode.hpp | 105 +- include/cinatra/use_asio.hpp | 20 +- include/cinatra/utils.hpp | 1317 +- include/cinatra/websocket.hpp | 485 +- include/cinatra/ws_define.h | 268 +- 43 files changed, 26476 insertions(+), 27384 deletions(-) diff --git a/example/example.vcxproj b/example/example.vcxproj index 5d37115..6a58470 100644 --- a/example/example.vcxproj +++ b/example/example.vcxproj @@ -95,7 +95,7 @@ stdcpp17 4996 /bigobj %(AdditionalOptions) - __SSE4_2__;CINATRA_ENABLE_SSL;%(PreprocessorDefinitions) + %(PreprocessorDefinitions) diff --git a/example/main.cpp b/example/main.cpp index 1bb0c1e..2ab8335 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -1,233 +1,219 @@ -#include #include "../include/cinatra.hpp" +#include using namespace cinatra; -struct log_t -{ - bool before(request& req, response& res) { - std::cout << "before log" << std::endl; - return true; - } - - bool after(request& req, response& res) { - std::cout << "after log" << std::endl; - res.add_header("aaaa", "bbcc"); - return true; - } +struct log_t { + bool before(request &req, response &res) { + std::cout << "before log" << std::endl; + return true; + } + + bool after(request &req, response &res) { + std::cout << "after log" << std::endl; + res.add_header("aaaa", "bbcc"); + return true; + } }; -struct person -{ - void foo(request& req, response& res) - { - std::cout << i << std::endl; - res.render_string("ok"); - } - - void foo1(request& req, response& res) - { - std::cout << i << std::endl; - res.render_string("ok"); - } - - int i=0; +struct person { + void foo(request &req, response &res) { + std::cout << i << std::endl; + res.render_string("ok"); + } + + void foo1(request &req, response &res) { + std::cout << i << std::endl; + res.render_string("ok"); + } + + int i = 0; }; -void test_ssl_server(){ +void test_ssl_server() { #ifdef CINATRA_ENABLE_SSL - //you should open macro CINATRA_ENABLE_SSL at first - http_ssl_server server(2); + // you should open macro CINATRA_ENABLE_SSL at first + http_ssl_server server(2); - server.set_ssl_conf({ "server.crt", "server.key" }); - int r = server.listen("0.0.0.0", "9001"); - if (r < 0) { - return; - } + server.set_ssl_conf({"server.crt", "server.key"}); + int r = server.listen("0.0.0.0", "9001"); + if (r < 0) { + return; + } - server.set_http_handler("/", [](request& req, response& res) { - auto str = req.get_conn()->remote_address(); - res.set_status_and_content(status_type::ok, "hello world from 9001"); - }); + server.set_http_handler("/", [](request &req, response &res) { + auto str = req.get_conn()->remote_address(); + res.set_status_and_content(status_type::ok, "hello world from 9001"); + }); - server.run(); + server.run(); #endif } -void print(const response_data& result) { - print(result.ec, result.status, result.resp_body, result.resp_headers.second); +void print(const response_data &result) { + print(result.ec, result.status, result.resp_body, result.resp_headers.second); } void test_sync_client() { - auto client = cinatra::client_factory::instance().new_client(); - std::string uri = "http://www.baidu.com"; - std::string uri1 = "http://cn.bing.com"; - std::string uri2 = "https://www.baidu.com"; - std::string uri3 = "https://cn.bing.com"; + auto client = cinatra::client_factory::instance().new_client(); + std::string uri = "http://www.baidu.com"; + std::string uri1 = "http://cn.bing.com"; + std::string uri2 = "https://www.baidu.com"; + std::string uri3 = "https://cn.bing.com"; - response_data result = client->get(uri); - print(result); + response_data result = client->get(uri); + print(result); - response_data result1 = client->get(uri1); - print(result1); + response_data result1 = client->get(uri1); + print(result1); - print(client->post(uri, "hello", req_content_type::json)); - print(client->post(uri1, "hello")); + print(client->post(uri, "hello", req_content_type::json)); + print(client->post(uri1, "hello")); #ifdef CINATRA_ENABLE_SSL - response_data result2 = client->get(uri2); - ////if you need to verify peer - //client->set_ssl_context_callback([](boost::asio::ssl::context& ctx) { - // ctx.set_verify_mode(boost::asio::ssl::context::verify_peer); - // ctx.load_verify_file("server.crt"); - - // //ctx.set_options( - // // boost::asio::ssl::context::default_workarounds - // // | boost::asio::ssl::context::no_sslv2 - // // | boost::asio::ssl::context::single_dh_use); - - // //ctx.use_certificate_chain_file("server.crt"); - // //ctx.use_private_key_file("server.key", boost::asio::ssl::context::pem); - // //ctx.use_tmp_dh_file("dh512.pem"); - //}); + response_data result2 = client->get(uri2); + ////if you need to verify peer + // client->set_ssl_context_callback([](boost::asio::ssl::context& ctx) { + // ctx.set_verify_mode(boost::asio::ssl::context::verify_peer); + // ctx.load_verify_file("server.crt"); + + // //ctx.set_options( + // // boost::asio::ssl::context::default_workarounds + // // | boost::asio::ssl::context::no_sslv2 + // // | boost::asio::ssl::context::single_dh_use); + + // //ctx.use_certificate_chain_file("server.crt"); + // //ctx.use_private_key_file("server.key", + // boost::asio::ssl::context::pem); + // //ctx.use_tmp_dh_file("dh512.pem"); + //}); - print(result2); + print(result2); - response_data result3 = client->get(uri3); - print(result3); + response_data result3 = client->get(uri3); + print(result3); - response_data result33 = client->get(uri); - print(result33); + response_data result33 = client->get(uri); + print(result33); - response_data result4 = client->get(uri3); - print(result4); + response_data result4 = client->get(uri3); + print(result4); - response_data result5 = client->get(uri2); - print(result5); + response_data result5 = client->get(uri2); + print(result5); #endif } void test_async_client() { - - std::string uri = "http://www.baidu.com"; - std::string uri1 = "http://cn.bing.com"; - std::string uri2 = "https://www.baidu.com"; - std::string uri3 = "https://cn.bing.com"; - - { - auto client = cinatra::client_factory::instance().new_client(); - client->async_get(uri, [](response_data data) { - print(data); - }); - } - - { - auto client = cinatra::client_factory::instance().new_client(); - client->async_get(uri1, [](response_data data) { - print(data); - }); - } - { - auto client = cinatra::client_factory::instance().new_client(); - client->async_post(uri, "hello", [](response_data data) { - print(data); - }); - } + std::string uri = "http://www.baidu.com"; + std::string uri1 = "http://cn.bing.com"; + std::string uri2 = "https://www.baidu.com"; + std::string uri3 = "https://cn.bing.com"; + + { + auto client = cinatra::client_factory::instance().new_client(); + client->async_get(uri, [](response_data data) { print(data); }); + } + + { + auto client = cinatra::client_factory::instance().new_client(); + client->async_get(uri1, [](response_data data) { print(data); }); + } + + { + auto client = cinatra::client_factory::instance().new_client(); + client->async_post(uri, "hello", [](response_data data) { print(data); }); + } #ifdef CINATRA_ENABLE_SSL - { - auto client = cinatra::client_factory::instance().new_client(); - client->async_get(uri2, [](response_data data) { - print(data); - }); - } + { + auto client = cinatra::client_factory::instance().new_client(); + client->async_get(uri2, [](response_data data) { print(data); }); + } - { - auto client = cinatra::client_factory::instance().new_client(); - client->async_get(uri3, [](response_data data) { - print(data); - }); - } + { + auto client = cinatra::client_factory::instance().new_client(); + client->async_get(uri3, [](response_data data) { print(data); }); + } #endif } void test_download() { - std::string uri = "http://www.httpwatch.com/httpgallery/chunked/chunkedimage.aspx"; - - { - auto client = cinatra::client_factory::instance().new_client(); - //Note: if the dest file has already exist, the file will be appened. - //If you want to download a new file, make sure no such a file with the same name. - //You could set the start position of the download file, eg: - //int64_t start_pos = 100; - //client->download(uri, "test1.jpg", start_pos, [](response_data data)... - client->download(uri, "test1.jpg", [](response_data data) { - if (data.ec) { - std::cout << data.ec.message() << "\n"; - return; - } - - std::cout << "finished download\n"; - }); - } + std::string uri = + "http://www.httpwatch.com/httpgallery/chunked/chunkedimage.aspx"; - { - auto client = cinatra::client_factory::instance().new_client(); - client->download(uri, [](auto ec, auto data) { - if (ec) { - std::cout << ec.message() << "\n"; - return; - } - - if (data.empty()) { - std::cout << "finished all \n"; - } - else { - std::cout << data.size() << "\n"; - } - }); - } -} + { + auto client = cinatra::client_factory::instance().new_client(); + // Note: if the dest file has already exist, the file will be appened. + // If you want to download a new file, make sure no such a file with the + // same name. You could set the start position of the download file, eg: + // int64_t start_pos = 100; + // client->download(uri, "test1.jpg", start_pos, [](response_data data)... + client->download(uri, "test1.jpg", [](response_data data) { + if (data.ec) { + std::cout << data.ec.message() << "\n"; + return; + } -void test_upload() { - std::string uri = "http://cn.bing.com/"; + std::cout << "finished download\n"; + }); + } + + { auto client = cinatra::client_factory::instance().new_client(); - client->upload(uri, "boost_1_72_0.7z", [](response_data data) { - if (data.ec) { - std::cout << data.ec.message() << "\n"; - return; - } + client->download(uri, [](auto ec, auto data) { + if (ec) { + std::cout << ec.message() << "\n"; + return; + } - std::cout << data.resp_body << "\n"; //finished upload + if (data.empty()) { + std::cout << "finished all \n"; + } else { + std::cout << data.size() << "\n"; + } }); + } } -class qps { -public: - void increase() { - counter_.fetch_add(1, std::memory_order_release); +void test_upload() { + std::string uri = "http://cn.bing.com/"; + auto client = cinatra::client_factory::instance().new_client(); + client->upload(uri, "boost_1_72_0.7z", [](response_data data) { + if (data.ec) { + std::cout << data.ec.message() << "\n"; + return; } - qps() : counter_(0) { - thd_ = std::thread([this] { - while (!stop_) { - std::cout << "qps: " << counter_.load(std::memory_order_acquire) << '\n'; - std::this_thread::sleep_for(std::chrono::seconds(1)); - //counter_.store(0, std::memory_order_release); - } - }); - } + std::cout << data.resp_body << "\n"; // finished upload + }); +} - ~qps() { - stop_ = true; - thd_.join(); - } +class qps { +public: + void increase() { counter_.fetch_add(1, std::memory_order_release); } + + qps() : counter_(0) { + thd_ = std::thread([this] { + while (!stop_) { + std::cout << "qps: " << counter_.load(std::memory_order_acquire) + << '\n'; + std::this_thread::sleep_for(std::chrono::seconds(1)); + // counter_.store(0, std::memory_order_release); + } + }); + } + + ~qps() { + stop_ = true; + thd_.join(); + } private: - bool stop_ = false; - std::thread thd_; - std::atomic counter_; + bool stop_ = false; + std::thread thd_; + std::atomic counter_; }; int main() { @@ -251,12 +237,14 @@ int main() { }); server.set_http_handler("/plaintext", [](request &req, response &res) { - // res.set_status_and_content("Hello, World!"); + // res.set_status_and_content("Hello, World!"); res.set_status_and_content(status_type::ok, "Hello, World!", req_content_type::string); }); - // server.set_http_handler("/delay", [](request& req, response& res) { + // server.set_http_handler("/delay", [](request& req, response& + // res) { // auto conn = req.get_conn(); // //monitor an async operation to test response delay @@ -275,39 +263,54 @@ int main() { //}); // person p{ 2 }; - // server.set_http_handler("/a", &person::foo, enable_cache{ false }, log_t{}); - //// server.set_http_handler("/b", &person::foo1, log_t{}, enable_cache{ false }); + // server.set_http_handler("/a", &person::foo, enable_cache{ + //false }, log_t{}); + //// server.set_http_handler("/b", &person::foo1, log_t{}, + ///enable_cache{ false }); // - // server.set_http_handler("/string", [](request& req, response& res) { + // server.set_http_handler("/string", [](request& req, response& + // res) { // res.render_string(std::to_string(std::time(nullptr))); // },enable_cache{true}); // - // server.set_http_handler("/404", [](request& req, response& res) { + // server.set_http_handler("/404", [](request& req, response& + // res) { // res.render_404(); // },enable_cache{false}); // - // server.set_http_handler("/404_custom", [](request& req, response& res) { + // server.set_http_handler("/404_custom", [](request& req, + // response& res) { // res.render_404("./404.html"); // },enable_cache{false}); // - // server.set_http_handler("/login", [](request& req, response& res) { auto session = res.start_session(); session->set_data("userid", std::string("1")); session->set_max_age(-1); - // res.set_status_and_content(status_type::ok, "login"); + // server.set_http_handler("/login", [](request& req, response& + //res) { auto session = res.start_session(); + //session->set_data("userid", std::string("1")); + //session->set_max_age(-1); res.set_status_and_content(status_type::ok, + //"login"); // },enable_cache{false}); // - // server.set_http_handler("/islogin", [](request& req, response& res) { auto ptr = req.get_session(); auto session = ptr.lock(); if (session == nullptr || session->get_data("userid") != "1") { - // res.set_status_and_content(status_type::ok, "没有登录", res_content_type::string); return; + // server.set_http_handler("/islogin", [](request& req, + //response& res) { auto ptr = req.get_session(); auto session + //= ptr.lock(); if (session == nullptr || + //session->get_data("userid") != "1") { + // res.set_status_and_content(status_type::ok, "没有登录", + //res_content_type::string); return; // } - // res.set_status_and_content(status_type::ok, "已经登录", res_content_type::string); + // res.set_status_and_content(status_type::ok, "已经登录", + //res_content_type::string); // },enable_cache{false}); // - // server.set_http_handler("/html", [](request& req, response& res) { + // server.set_http_handler("/html", [](request& req, response& + //res) { // res.set_attr("number",1024); // res.set_attr("test_text","hello,world"); // res.set_attr("header_text","你好 cinatra"); // res.render_view("./www/test.html"); // }); // - // server.set_http_handler("/json", [](request& req, response& res) { nlohmann::json json; + // server.set_http_handler("/json", [](request& req, + //response& res) { nlohmann::json json; // res.add_header("Access-Control-Allow-Origin","*"); // if(req.get_method()=="OPTIONS"){ // res.add_header("Access-Control-Allow-Headers","Authorization"); @@ -322,14 +325,20 @@ int main() { // } // }); // - // server.set_http_handler("/redirect",[](request& req, response& res){ res.redirect("http://www.baidu.com"); // res.redirect("/json"); + // server.set_http_handler("/redirect",[](request& req, response& + //res){ res.redirect("http://www.baidu.com"); // + //res.redirect("/json"); // }); // - // server.set_http_handler("/pathinfo/*", [](request& req, response& res) { auto s = req.get_query_value(0); + // server.set_http_handler("/pathinfo/*", [](request& req, + //response& res) { auto s = req.get_query_value(0); // res.render_string(std::string(s.data(), s.length())); // }); // - // server.set_http_handler("/restype", [](request& req, response& res) { auto type = req.get_query_value("type"); auto res_type = cinatra::res_content_type::string; if (type == "html") + // server.set_http_handler("/restype", [](request& req, + //response& res) { auto type = req.get_query_value("type"); + //auto res_type = cinatra::res_content_type::string; if (type == + //"html") // { // res_type = cinatra::res_content_type::html; // } @@ -339,21 +348,25 @@ int main() { // else if (type == "string") { // //do not anything; // } - // res.set_status_and_content(status_type::ok, "hello world 百度", res_type); + // res.set_status_and_content(status_type::ok, "hello world 百度", res_type); // }); // - // server.set_http_handler("/getzh", [](request& req, response& res) { auto zh = req.get_query_value("zh"); + // server.set_http_handler("/getzh", [](request& req, response& + //res) { auto zh = req.get_query_value("zh"); // res.render_string(std::string(zh.data(),zh.size())); // }); // - // server.set_http_handler("/gzip", [](request& req, response& res) { auto body = req.body(); std::cout << body.data() << std::endl; - // res.set_status_and_content(status_type::ok, "hello world", res_content_type::none, content_encoding::gzip); + // server.set_http_handler("/gzip", [](request& req, response& + //res) { auto body = req.body(); std::cout << body.data() << + //std::endl; res.set_status_and_content(status_type::ok, "hello world", + //res_content_type::none, content_encoding::gzip); // }); // // - // server.set_http_handler("/test", [](request& req, response& res) { auto name = req.get_header_value("name"); if (name.empty()) { - // res.render_string("no name"); - // return; + // server.set_http_handler("/test", [](request& req, response& + //res) { auto name = req.get_header_value("name"); if + //(name.empty()) { res.render_string("no name"); return; // } // // auto id = req.get_query_value("id"); @@ -365,7 +378,8 @@ int main() { // }); // // //aspect - // server.set_http_handler("/aspect", [](request& req, response& res) { res.render_string("hello world"); + // server.set_http_handler("/aspect", [](request& req, response& + //res) { res.render_string("hello world"); // }, check{}, log_t{}); // ////web socket @@ -379,39 +393,51 @@ int main() { // req.on(ws_message, [](request& req) { // auto part_data = req.get_part_data(); // //echo - // std::string str = std::string(part_data.data(), part_data.length()); req.get_conn()->send_ws_string(std::move(str)); - // std::cout << part_data.data() << std::endl; + // std::string str = std::string(part_data.data(), part_data.length()); + //req.get_conn()->send_ws_string(std::move(str)); std::cout << + //part_data.data() << std::endl; // }); // req.on(ws_error, [](request& req) { - // std::cout << "websocket pack error or network error" << std::endl; + // std::cout << "websocket pack error or network error" << + //std::endl; // }); //}); - // server.set_http_handler("/vue_html", [](request& req, response& res) { res.render_raw_view("./www/index.html"); + // server.set_http_handler("/vue_html", [](request& req, + //response& res) { res.render_raw_view("./www/index.html"); // }); // - // server.set_http_handler("/vue_demo", [](request& req, response& res) { res.render_raw_view("./www/dist/index.html"); + // server.set_http_handler("/vue_demo", [](request& req, + //response& res) { res.render_raw_view("./www/dist/index.html"); // }); // // //http upload(multipart) - // server.set_http_handler("/upload_multipart", [](request& req, response& res) { assert(req.get_content_type() == content_type::multipart); + // server.set_http_handler("/upload_multipart", [](request& req, + // response& res) { assert(req.get_content_type() == + // content_type::multipart); // auto& files = req.get_upload_files(); // for (auto& file : files) { - // std::cout << file.get_file_path() << " " << file.get_file_size() << std::endl; + // std::cout << file.get_file_path() << " " << file.get_file_size() << + //std::endl; // } // res.render_string("multipart finished"); //}); // // //http upload(octet-stream) - // server.set_http_handler("/upload_octet_stream", [](request& req, response& res) { assert(req.get_content_type() == content_type::octet_stream); auto& files = req.get_upload_files(); for (auto& file : files) { std::cout << file.get_file_path() << " " << file.get_file_size() << std::endl; + // server.set_http_handler("/upload_octet_stream", [](request& + //req, response& res) { assert(req.get_content_type() == + //content_type::octet_stream); auto& files = req.get_upload_files(); + //for (auto& file : files) { std::cout << file.get_file_path() << + //" " << file.get_file_size() << std::endl; // } // res.render_string("octet-stream finished"); // }); // chunked download // http://127.0.0.1:8080/assets/show.jpg - // cinatra will send you the file, if the file is big file(more than 5M) the file will be downloaded by chunked + // cinatra will send you the file, if the file is big file(more than 5M) the + // file will be downloaded by chunked server.run(); return 0; } \ No newline at end of file diff --git a/include/cinatra.hpp b/include/cinatra.hpp index 5db471a..eab3610 100644 --- a/include/cinatra.hpp +++ b/include/cinatra.hpp @@ -5,7 +5,7 @@ #ifndef CINATRA_CINATRA_HPP #define CINATRA_CINATRA_HPP -#include "cinatra/http_server.hpp" #include "cinatra/client_factory.hpp" +#include "cinatra/http_server.hpp" -#endif //CINATRA_CINATRA_HPP +#endif // CINATRA_CINATRA_HPP diff --git a/include/cinatra/async_client.hpp b/include/cinatra/async_client.hpp index 882019d..b697a8c 100644 --- a/include/cinatra/async_client.hpp +++ b/include/cinatra/async_client.hpp @@ -1,511 +1,534 @@ #pragma once -#include -#include -#include +#include "http_parser.hpp" #include "uri.hpp" #include "use_asio.hpp" -#include "http_parser.hpp" +#include +#include +#include namespace cinatra { - class async_client : public std::enable_shared_from_this { - public: - async_client(boost::asio::io_service& ios) : ios_(ios), resolver_(ios), socket_(ios){ - } - - ~async_client() { - close(); - } - - bool connect(std::string uri, size_t timeout_seconds) { - auto [r, u] = get_uri(uri); - if (!r) { - return false; - } - - auto promise = std::make_shared>(); - std::weak_ptr> weak(promise); - host_ = u.get_host(); - - async_connect(host_, u.get_port(), weak); - - auto future = promise->get_future(); - auto status = future.wait_for(std::chrono::seconds(timeout_seconds)); - if (status == std::future_status::timeout) { - promise = nullptr; - close(false); - return false; - } - - r = future.get(); - promise = nullptr; - return r; - } - - void on_data(callback_t cb) { - cb_ = std::move(cb); - } - - void async_request(std::string_view method, std::string_view url, const std::vector>& headers, - std::string_view body) { - std::string write_msg = make_write_msg(method, url, headers, body); - std::unique_lock lock(write_mtx_); - outbox_.emplace_back(std::move(write_msg)); - if (outbox_.size() > 1) { - return; - } - - write(); - } - - bool has_connected() const { - return has_connected_; - } - - private: - void async_connect(const std::string& host, const std::string& port, std::weak_ptr> weak) { - boost::asio::ip::tcp::resolver::query query(host, port); - resolver_.async_resolve(query, [this, self = this->shared_from_this(), weak] - (boost::system::error_code ec, const boost::asio::ip::tcp::resolver::iterator& it) { - if (ec) { - if (auto sp = weak.lock(); sp) - sp->set_value(false); +class async_client : public std::enable_shared_from_this { +public: + async_client(boost::asio::io_service &ios) + : ios_(ios), resolver_(ios), socket_(ios) {} + + ~async_client() { close(); } + + bool connect(std::string uri, size_t timeout_seconds) { + auto [r, u] = get_uri(uri); + if (!r) { + return false; + } + + auto promise = std::make_shared>(); + std::weak_ptr> weak(promise); + host_ = u.get_host(); + + async_connect(host_, u.get_port(), weak); + + auto future = promise->get_future(); + auto status = future.wait_for(std::chrono::seconds(timeout_seconds)); + if (status == std::future_status::timeout) { + promise = nullptr; + close(false); + return false; + } + + r = future.get(); + promise = nullptr; + return r; + } + + void on_data(callback_t cb) { cb_ = std::move(cb); } + + void + async_request(std::string_view method, std::string_view url, + const std::vector> &headers, + std::string_view body) { + std::string write_msg = make_write_msg(method, url, headers, body); + std::unique_lock lock(write_mtx_); + outbox_.emplace_back(std::move(write_msg)); + if (outbox_.size() > 1) { + return; + } + + write(); + } + + bool has_connected() const { return has_connected_; } + +private: + void async_connect(const std::string &host, const std::string &port, + std::weak_ptr> weak) { + boost::asio::ip::tcp::resolver::query query(host, port); + resolver_.async_resolve( + query, [this, self = this->shared_from_this(), + weak](boost::system::error_code ec, + const boost::asio::ip::tcp::resolver::iterator &it) { + if (ec) { + if (auto sp = weak.lock(); sp) + sp->set_value(false); + return; + } + + boost::asio::async_connect( + socket_, it, + [this, self = shared_from_this(), + weak](boost::system::error_code ec, + const boost::asio::ip::tcp::resolver::iterator &) { + if (!ec) { + has_connected_ = true; + if (is_ssl()) { + handshake(weak); return; - } - - boost::asio::async_connect(socket_, it, [this, self = shared_from_this(), weak] - (boost::system::error_code ec, const boost::asio::ip::tcp::resolver::iterator&) { - if (!ec) { - has_connected_ = true; - if (is_ssl()) { - handshake(weak); - return; - } - - do_read(); - } - else { - close(); - } - - if (auto sp = weak.lock(); sp) - sp->set_value(has_connected_); - }); - }); - } + } - void handshake(std::weak_ptr> weak) { -#ifdef CINATRA_ENABLE_SSL - auto self = this->shared_from_this(); - ssl_stream_->async_handshake(boost::asio::ssl::stream_base::client, - [this, self, weak](const boost::system::error_code& ec) { - if (!ec) { - do_read(); - } - else { - close(); + do_read(); + } else { + close(); } if (auto sp = weak.lock(); sp) - sp->set_value(has_connected_); - }); -#endif - } - - void do_read() { - async_read_until(TWO_CRCF, [this, self = shared_from_this()](auto ec, size_t size) { - if (ec) { - close(); - return; - } - - const char* data_ptr = boost::asio::buffer_cast(read_buf_.data()); - size_t buf_size = read_buf_.size(); - - int ret = parser_.parse_response(data_ptr, size, 0); - read_buf_.consume(size); - if (ret < 0) { - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), 404, - RESP_PARSE_ERROR); - if (buf_size > size) { - read_buf_.consume(buf_size - size); - } + sp->set_value(has_connected_); + }); + }); + } - read_or_close(parser_.keep_alive()); - return; - } - - bool is_chunked = parser_.is_chunked(); + void handshake(std::weak_ptr> weak) { +#ifdef CINATRA_ENABLE_SSL + auto self = this->shared_from_this(); + ssl_stream_->async_handshake( + boost::asio::ssl::stream_base::client, + [this, self, weak](const boost::system::error_code &ec) { + if (!ec) { + do_read(); + } else { + close(); + } - if (is_chunked) { - copy_headers(); - //read_chunk_header - read_chunk_head(parser_.keep_alive()); - } - else { - if (parser_.body_len() == 0) { - callback(ec, parser_.status()); - - read_or_close(parser_.keep_alive()); - return; - } - - size_t content_len = (size_t)parser_.body_len(); - if ((size_t)parser_.total_len() <= buf_size) { - callback(ec, parser_.status(), { data_ptr + parser_.header_len(), content_len }); - read_buf_.consume(content_len); - - read_or_close(parser_.keep_alive()); - return; - } - - size_t size_to_read = content_len - read_buf_.size(); - copy_headers(); - do_read_body(parser_.keep_alive(), parser_.status(), size_to_read); - } - }); - } + if (auto sp = weak.lock(); sp) + sp->set_value(has_connected_); + }); +#endif + } - void do_read_body(bool keep_alive, int status, size_t size_to_read) { - async_read(size_to_read, [this, self = shared_from_this(), keep_alive, status](auto ec, size_t size) { - if (!ec) { - size_t data_size = read_buf_.size(); - const char* data_ptr = boost::asio::buffer_cast(read_buf_.data()); + void do_read() { + async_read_until( + TWO_CRCF, [this, self = shared_from_this()](auto ec, size_t size) { + if (ec) { + close(); + return; + } + + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + size_t buf_size = read_buf_.size(); + + int ret = parser_.parse_response(data_ptr, size, 0); + read_buf_.consume(size); + if (ret < 0) { + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, RESP_PARSE_ERROR); + if (buf_size > size) { + read_buf_.consume(buf_size - size); + } - callback(ec, status, { data_ptr, data_size }); + read_or_close(parser_.keep_alive()); + return; + } - read_buf_.consume(data_size); + bool is_chunked = parser_.is_chunked(); - read_or_close(keep_alive); - } - else { - callback(ec); - close(); - } - }); - } + if (is_chunked) { + copy_headers(); + // read_chunk_header + read_chunk_head(parser_.keep_alive()); + } else { + if (parser_.body_len() == 0) { + callback(ec, parser_.status()); - void read_or_close(bool keep_alive) { - if (keep_alive) { - do_read(); + read_or_close(parser_.keep_alive()); + return; } - else { - close(); - } - } - void read_chunk_head(bool keep_alive) { - async_read_until(CRCF, [this, self = shared_from_this(), keep_alive](auto ec, size_t size) { - if (!ec) { - size_t buf_size = read_buf_.size(); - const char* data_ptr = boost::asio::buffer_cast(read_buf_.data()); - std::string_view size_str(data_ptr, size - CRCF.size()); - auto chunk_size = hex_to_int(size_str); - if (chunk_size < 0) { - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), 404, - INVALID_CHUNK_SIZE); - read_or_close(keep_alive); - return; - } - - read_buf_.consume(size); - - if (chunk_size == 0) { - if (read_buf_.size() < CRCF.size()) { - read_buf_.consume(read_buf_.size()); - read_chunk_body(keep_alive, CRCF.size() - read_buf_.size()); - } - else { - read_buf_.consume(CRCF.size()); - read_chunk_body(keep_alive, 0); - } - return; - } - - if ((size_t)chunk_size <= read_buf_.size()) { - const char* data = boost::asio::buffer_cast(read_buf_.data()); - append_chunk(std::string_view(data, chunk_size)); - read_buf_.consume(chunk_size + CRCF.size()); - read_chunk_head(keep_alive); - return; - } - - size_t extra_size = read_buf_.size(); - size_t size_to_read = chunk_size - extra_size; - const char* data = boost::asio::buffer_cast(read_buf_.data()); - append_chunk({ data, extra_size }); - read_buf_.consume(extra_size); - - read_chunk_body(keep_alive, size_to_read + CRCF.size()); - } - else { - callback(ec); - close(); - } - }); - } - - void read_chunk_body(bool keep_alive, size_t size_to_read) { - async_read(size_to_read, [this, self = shared_from_this(), keep_alive](auto ec, size_t size) { - if (!ec) { - if (size <= CRCF.size()) { - //finish all chunked - read_buf_.consume(size); - callback(ec, 200, chunked_result_); - clear_chunk_buffer(); - do_read(); - return; - } - - size_t buf_size = read_buf_.size(); - const char* data_ptr = boost::asio::buffer_cast(read_buf_.data()); - append_chunk({ data_ptr, size - CRCF.size() }); - read_buf_.consume(size); - read_chunk_head(keep_alive); - } - else { - callback(ec); - close(); - } - }); - } - - void append_chunk(std::string_view chunk) { - chunked_result_.append(chunk); - } + size_t content_len = (size_t)parser_.body_len(); + if ((size_t)parser_.total_len() <= buf_size) { + callback(ec, parser_.status(), + {data_ptr + parser_.header_len(), content_len}); + read_buf_.consume(content_len); - void clear_chunk_buffer() { - if (!chunked_result_.empty()) { - chunked_result_.clear(); + read_or_close(parser_.keep_alive()); + return; } - } - void callback(const boost::system::error_code& ec) { - callback(ec, 404, ""); + size_t size_to_read = content_len - read_buf_.size(); + copy_headers(); + do_read_body(parser_.keep_alive(), parser_.status(), size_to_read); + } + }); + } + + void do_read_body(bool keep_alive, int status, size_t size_to_read) { + async_read(size_to_read, [this, self = shared_from_this(), keep_alive, + status](auto ec, size_t size) { + if (!ec) { + size_t data_size = read_buf_.size(); + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + + callback(ec, status, {data_ptr, data_size}); + + read_buf_.consume(data_size); + + read_or_close(keep_alive); + } else { + callback(ec); + close(); + } + }); + } + + void read_or_close(bool keep_alive) { + if (keep_alive) { + do_read(); + } else { + close(); + } + } + + void read_chunk_head(bool keep_alive) { + async_read_until(CRCF, [this, self = shared_from_this(), + keep_alive](auto ec, size_t size) { + if (!ec) { + size_t buf_size = read_buf_.size(); + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + std::string_view size_str(data_ptr, size - CRCF.size()); + auto chunk_size = hex_to_int(size_str); + if (chunk_size < 0) { + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, INVALID_CHUNK_SIZE); + read_or_close(keep_alive); + return; } - void callback(const boost::system::error_code& ec, std::string error_msg) { - callback(ec, 404, std::move(error_msg)); + read_buf_.consume(size); + + if (chunk_size == 0) { + if (read_buf_.size() < CRCF.size()) { + read_buf_.consume(read_buf_.size()); + read_chunk_body(keep_alive, CRCF.size() - read_buf_.size()); + } else { + read_buf_.consume(CRCF.size()); + read_chunk_body(keep_alive, 0); + } + return; } - void callback(const boost::system::error_code& ec, int status) { - callback(ec, status, ""); + if ((size_t)chunk_size <= read_buf_.size()) { + const char *data = + boost::asio::buffer_cast(read_buf_.data()); + append_chunk(std::string_view(data, chunk_size)); + read_buf_.consume(chunk_size + CRCF.size()); + read_chunk_head(keep_alive); + return; } - void callback(const boost::system::error_code& ec, int status, std::string_view result) { - if (cb_) { - cb_({ ec, status, result, get_resp_headers() }); - } + size_t extra_size = read_buf_.size(); + size_t size_to_read = chunk_size - extra_size; + const char *data = + boost::asio::buffer_cast(read_buf_.data()); + append_chunk({data, extra_size}); + read_buf_.consume(extra_size); + + read_chunk_body(keep_alive, size_to_read + CRCF.size()); + } else { + callback(ec); + close(); + } + }); + } + + void read_chunk_body(bool keep_alive, size_t size_to_read) { + async_read(size_to_read, [this, self = shared_from_this(), + keep_alive](auto ec, size_t size) { + if (!ec) { + if (size <= CRCF.size()) { + // finish all chunked + read_buf_.consume(size); + callback(ec, 200, chunked_result_); + clear_chunk_buffer(); + do_read(); + return; } - std::string make_write_msg(std::string_view method, std::string_view url, const std::vector>& headers, - std::string_view body) { - std::string write_msg(method); - //can be optimized here - write_msg.append(" ").append(url); - - write_msg.append(" HTTP/1.1\r\nHost:"). - append(host_).append("\r\n"); - - bool has_connection = false; - //add user header - if (!headers.empty()) { - for (auto& pair : headers) { - if (pair.first == "Connection") { - has_connection = true; - } - write_msg.append(pair.first).append(": ").append(pair.second).append("\r\n"); - } - } - - //add content - if (!body.empty()) { - char buffer[20]; - auto p = i32toa_jeaiii((int)body.size(), buffer); - - write_msg.append("Content-Length: ").append(buffer, p - buffer).append("\r\n"); - } - else { - if (method == "POST"sv) { - write_msg.append("Content-Length: 0\r\n"); - } - } - - if (!has_connection) { - write_msg.append("Connection: keep-alive\r\n"); - } - - write_msg.append("\r\n"); - - if (!body.empty()) { - write_msg.append(body); - } - - return write_msg; + size_t buf_size = read_buf_.size(); + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + append_chunk({data_ptr, size - CRCF.size()}); + read_buf_.consume(size); + read_chunk_head(keep_alive); + } else { + callback(ec); + close(); + } + }); + } + + void append_chunk(std::string_view chunk) { chunked_result_.append(chunk); } + + void clear_chunk_buffer() { + if (!chunked_result_.empty()) { + chunked_result_.clear(); + } + } + + void callback(const boost::system::error_code &ec) { callback(ec, 404, ""); } + + void callback(const boost::system::error_code &ec, std::string error_msg) { + callback(ec, 404, std::move(error_msg)); + } + + void callback(const boost::system::error_code &ec, int status) { + callback(ec, status, ""); + } + + void callback(const boost::system::error_code &ec, int status, + std::string_view result) { + if (cb_) { + cb_({ec, status, result, get_resp_headers()}); + } + } + + std::string make_write_msg( + std::string_view method, std::string_view url, + const std::vector> &headers, + std::string_view body) { + std::string write_msg(method); + // can be optimized here + write_msg.append(" ").append(url); + + write_msg.append(" HTTP/1.1\r\nHost:").append(host_).append("\r\n"); + + bool has_connection = false; + // add user header + if (!headers.empty()) { + for (auto &pair : headers) { + if (pair.first == "Connection") { + has_connection = true; } - - void write() { - auto& msg = outbox_[0]; - async_write(msg, [this, self = shared_from_this()](const boost::system::error_code& ec, const size_t length) { - if (ec) { - //print(ec); + write_msg.append(pair.first) + .append(": ") + .append(pair.second) + .append("\r\n"); + } + } + + // add content + if (!body.empty()) { + char buffer[20]; + auto p = i32toa_jeaiii((int)body.size(), buffer); + + write_msg.append("Content-Length: ") + .append(buffer, p - buffer) + .append("\r\n"); + } else { + if (method == "POST"sv) { + write_msg.append("Content-Length: 0\r\n"); + } + } + + if (!has_connection) { + write_msg.append("Connection: keep-alive\r\n"); + } + + write_msg.append("\r\n"); + + if (!body.empty()) { + write_msg.append(body); + } + + return write_msg; + } + + void write() { + auto &msg = outbox_[0]; + async_write(msg, + [this, self = shared_from_this()]( + const boost::system::error_code &ec, const size_t length) { + if (ec) { + // print(ec); close(); return; - } + } - std::unique_lock lock(write_mtx_); - if (outbox_.empty()) { + std::unique_lock lock(write_mtx_); + if (outbox_.empty()) { return; - } + } - outbox_.pop_front(); + outbox_.pop_front(); - if (!outbox_.empty()) { + if (!outbox_.empty()) { // more messages to send write(); - } - }); - } + } + }); + } - template - void async_read(size_t size_to_read, Handler handler) { - if (is_ssl()) { + template + void async_read(size_t size_to_read, Handler handler) { + if (is_ssl()) { #ifdef CINATRA_ENABLE_SSL - boost::asio::async_read(*ssl_stream_, read_buf_, boost::asio::transfer_exactly(size_to_read), std::move(handler)); + boost::asio::async_read(*ssl_stream_, read_buf_, + boost::asio::transfer_exactly(size_to_read), + std::move(handler)); #endif - } - else { - boost::asio::async_read(socket_, read_buf_, boost::asio::transfer_exactly(size_to_read), std::move(handler)); - } - } - - template - void async_read_until(const std::string& delim, Handler handler) { - if (is_ssl()) { + } else { + boost::asio::async_read(socket_, read_buf_, + boost::asio::transfer_exactly(size_to_read), + std::move(handler)); + } + } + + template + void async_read_until(const std::string &delim, Handler handler) { + if (is_ssl()) { #ifdef CINATRA_ENABLE_SSL - boost::asio::async_read_until(*ssl_stream_, read_buf_, delim, std::move(handler)); + boost::asio::async_read_until(*ssl_stream_, read_buf_, delim, + std::move(handler)); #endif - } - else { - boost::asio::async_read_until(socket_, read_buf_, delim, std::move(handler)); - } - } - - template - void async_write(const std::string& msg, Handler handler) { - if (is_ssl()) { + } else { + boost::asio::async_read_until(socket_, read_buf_, delim, + std::move(handler)); + } + } + + template + void async_write(const std::string &msg, Handler handler) { + if (is_ssl()) { #ifdef CINATRA_ENABLE_SSL - boost::asio::async_write(*ssl_stream_, boost::asio::buffer(msg), std::move(handler)); + boost::asio::async_write(*ssl_stream_, boost::asio::buffer(msg), + std::move(handler)); #endif - } - else { - boost::asio::async_write(socket_, boost::asio::buffer(msg), std::move(handler)); - } - } + } else { + boost::asio::async_write(socket_, boost::asio::buffer(msg), + std::move(handler)); + } + } - bool is_ssl() const { + bool is_ssl() const { #ifdef CINATRA_ENABLE_SSL - return ssl_stream_ != nullptr; + return ssl_stream_ != nullptr; #else - return false; + return false; #endif - } + } #ifdef CINATRA_ENABLE_SSL - void upgrade_to_ssl(std::function ssl_context_callback) { - if (ssl_stream_) - return; - - boost::asio::ssl::context ssl_context(boost::asio::ssl::context::sslv23); - ssl_context.set_default_verify_paths(); - boost::system::error_code ec; - ssl_context.set_options(boost::asio::ssl::context::default_workarounds, ec); - if (ssl_context_callback) { - ssl_context_callback(ssl_context); - } - ssl_stream_ = std::make_unique>(socket_, ssl_context); - //verify peer TODO - } + void upgrade_to_ssl( + std::function ssl_context_callback) { + if (ssl_stream_) + return; + + boost::asio::ssl::context ssl_context(boost::asio::ssl::context::sslv23); + ssl_context.set_default_verify_paths(); + boost::system::error_code ec; + ssl_context.set_options(boost::asio::ssl::context::default_workarounds, ec); + if (ssl_context_callback) { + ssl_context_callback(ssl_context); + } + ssl_stream_ = std::make_unique< + boost::asio::ssl::stream>(socket_, + ssl_context); + // verify peer TODO + } #endif - void close(bool close_ssl = true) { - boost::system::error_code ec; - if (close_ssl) { + void close(bool close_ssl = true) { + boost::system::error_code ec; + if (close_ssl) { #ifdef CINATRA_ENABLE_SSL - if (ssl_stream_) { - ssl_stream_->shutdown(ec); - ssl_stream_ = nullptr; - } + if (ssl_stream_) { + ssl_stream_->shutdown(ec); + ssl_stream_ = nullptr; + } #endif - } + } - if (!has_connected_) - return; + if (!has_connected_) + return; - has_connected_ = false; - //timer_.cancel(ec); - socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - socket_.close(ec); - } + has_connected_ = false; + // timer_.cancel(ec); + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + socket_.close(ec); + } - std::pair get_uri(const std::string& uri) { - uri_t u; - if (!u.parse_from(uri.data())) { - if (u.schema.empty()) - return { false, {} }; + std::pair get_uri(const std::string &uri) { + uri_t u; + if (!u.parse_from(uri.data())) { + if (u.schema.empty()) + return {false, {}}; - auto new_uri = url_encode(uri); + auto new_uri = url_encode(uri); - if (!u.parse_from(new_uri.data())) { - return { false, {} }; - } - } + if (!u.parse_from(new_uri.data())) { + return {false, {}}; + } + } - if (u.schema == "https"sv) { + if (u.schema == "https"sv) { #ifdef CINATRA_ENABLE_SSL - upgrade_to_ssl(nullptr); + upgrade_to_ssl(nullptr); #else - //please open CINATRA_ENABLE_SSL before request https! - assert(false); + // please open CINATRA_ENABLE_SSL before request https! + assert(false); #endif - } - - return { true, u }; - } - - std::pair get_resp_headers() { - if (!copy_headers_.empty()) - parser_.set_headers(copy_headers_); - - return parser_.get_headers(); - } - - void copy_headers() { - if (!copy_headers_.empty()) { - copy_headers_.clear(); - } - auto [headers, num_headers] = parser_.get_headers(); - for (size_t i = 0; i < num_headers; i++) { - copy_headers_.emplace_back(std::string(headers[i].name, headers[i].name_len), - std::string(headers[i].value, headers[i].value_len)); - } - } - private: - boost::asio::io_service& ios_; - boost::asio::ip::tcp::resolver resolver_; - boost::asio::ip::tcp::socket socket_; - boost::asio::streambuf read_buf_; - std::deque outbox_; - std::mutex write_mtx_; - std::atomic_bool has_connected_ = false; + } + + return {true, u}; + } + + std::pair get_resp_headers() { + if (!copy_headers_.empty()) + parser_.set_headers(copy_headers_); + + return parser_.get_headers(); + } + + void copy_headers() { + if (!copy_headers_.empty()) { + copy_headers_.clear(); + } + auto [headers, num_headers] = parser_.get_headers(); + for (size_t i = 0; i < num_headers; i++) { + copy_headers_.emplace_back( + std::string(headers[i].name, headers[i].name_len), + std::string(headers[i].value, headers[i].value_len)); + } + } + +private: + boost::asio::io_service &ios_; + boost::asio::ip::tcp::resolver resolver_; + boost::asio::ip::tcp::socket socket_; + boost::asio::streambuf read_buf_; + std::deque outbox_; + std::mutex write_mtx_; + std::atomic_bool has_connected_ = false; #ifdef CINATRA_ENABLE_SSL - std::unique_ptr> ssl_stream_; + std::unique_ptr> + ssl_stream_; #endif - callback_t cb_; - std::string host_; + callback_t cb_; + std::string host_; - std::string chunked_result_; + std::string chunked_result_; - http_parser parser_; - std::vector> copy_headers_; - }; -} \ No newline at end of file + http_parser parser_; + std::vector> copy_headers_; +}; +} // namespace cinatra \ No newline at end of file diff --git a/include/cinatra/client_factory.hpp b/include/cinatra/client_factory.hpp index a9380bd..fe762a0 100644 --- a/include/cinatra/client_factory.hpp +++ b/include/cinatra/client_factory.hpp @@ -1,70 +1,67 @@ #pragma once -#include "http_client.hpp" #include "async_client.hpp" +#include "http_client.hpp" namespace cinatra { - class client_factory { - public: - static client_factory& instance() { - static client_factory instance; - return instance; - } +class client_factory { +public: + static client_factory &instance() { + static client_factory instance; + return instance; + } - template - auto new_client(Args&&... args) { - return std::make_shared(ios_, std::forward(args)...); - } + template auto new_client(Args &&...args) { + return std::make_shared(ios_, std::forward(args)...); + } - template - std::shared_ptr new_async_client(Args&& ... args) { - return std::make_shared(ios_, std::forward(args)...); - } + template + std::shared_ptr new_async_client(Args &&...args) { + return std::make_shared(ios_, std::forward(args)...); + } - void run() { - ios_.run(); - } + void run() { ios_.run(); } - void stop() { - ios_.stop(); - } + void stop() { ios_.stop(); } - private: - client_factory() : work_(ios_) { - thd_ = std::make_shared([this] {ios_.run(); }); - } +private: + client_factory() : work_(ios_) { + thd_ = std::make_shared([this] { ios_.run(); }); + } - ~client_factory() { - ios_.stop(); - thd_->join(); - } + ~client_factory() { + ios_.stop(); + thd_->join(); + } - client_factory(const client_factory&) = delete; - client_factory& operator=(const client_factory&) = delete; - client_factory(client_factory&&) = delete; - client_factory& operator=(client_factory&&) = delete; + client_factory(const client_factory &) = delete; + client_factory &operator=(const client_factory &) = delete; + client_factory(client_factory &&) = delete; + client_factory &operator=(client_factory &&) = delete; - boost::asio::io_service ios_; - boost::asio::io_service::work work_; - std::shared_ptr thd_; - }; + boost::asio::io_service ios_; + boost::asio::io_service::work work_; + std::shared_ptr thd_; +}; - //inline auto get(std::string uri, size_t timeout_seconds = 5) { - // auto client = cinatra::client_factory::instance().new_client(); - // return client->get(std::move(uri), timeout_seconds); - //} +// inline auto get(std::string uri, size_t timeout_seconds = 5) { +// auto client = cinatra::client_factory::instance().new_client(); +// return client->get(std::move(uri), timeout_seconds); +//} - //inline auto post(std::string uri, std::string body, size_t timeout_seconds = 5) { - // auto client = cinatra::client_factory::instance().new_client(); - // return client->post(std::move(uri), std::move(body), timeout_seconds); - //} +// inline auto post(std::string uri, std::string body, size_t timeout_seconds = +// 5) { +// auto client = cinatra::client_factory::instance().new_client(); +// return client->post(std::move(uri), std::move(body), timeout_seconds); +//} - //inline error_code async_get(std::string uri, callback_t cb) { - // auto client = cinatra::client_factory::instance().new_client(); - // return client->async_get(std::move(uri), std::move(cb)); - //} +// inline error_code async_get(std::string uri, callback_t cb) { +// auto client = cinatra::client_factory::instance().new_client(); +// return client->async_get(std::move(uri), std::move(cb)); +//} - //inline error_code async_post(std::string uri, std::string body, callback_t cb) { - // auto client = cinatra::client_factory::instance().new_client(); - // return client->async_post(std::move(uri), std::move(body), std::move(cb)); - //} -} \ No newline at end of file +// inline error_code async_post(std::string uri, std::string body, callback_t +// cb) { +// auto client = cinatra::client_factory::instance().new_client(); +// return client->async_post(std::move(uri), std::move(body), std::move(cb)); +//} +} // namespace cinatra \ No newline at end of file diff --git a/include/cinatra/connection.hpp b/include/cinatra/connection.hpp index 56c9639..e8006a4 100644 --- a/include/cinatra/connection.hpp +++ b/include/cinatra/connection.hpp @@ -1,14 +1,14 @@ #pragma once -#include "use_asio.hpp" -#include -#include -#include -#include +#include "define.h" +#include "http_cache.hpp" #include "request.hpp" #include "response.hpp" +#include "use_asio.hpp" #include "websocket.hpp" -#include "define.h" -#include "http_cache.hpp" +#include +#include +#include +#include namespace cinatra { using http_handler = std::function; @@ -85,7 +85,8 @@ public: #else static_assert( !is_ssl_, - "please add definition CINATRA_ENABLE_SSL"); // guard, not allowed coming in this branch + "please add definition CINATRA_ENABLE_SSL"); // guard, not allowed + // coming in this branch #endif } else { return socket_; @@ -180,16 +181,16 @@ public: auto &get_tag() { return tag_; } - template void send_ws_string(std::string msg, Fs &&... fs) { + template void send_ws_string(std::string msg, Fs &&...fs) { send_ws_msg(std::move(msg), opcode::text, std::forward(fs)...); } - template void send_ws_binary(std::string msg, Fs &&... fs) { + template void send_ws_binary(std::string msg, Fs &&...fs) { send_ws_msg(std::move(msg), opcode::binary, std::forward(fs)...); } template - void send_ws_msg(std::string msg, opcode op = opcode::text, Fs &&... fs) { + void send_ws_msg(std::string msg, opcode op = opcode::text, Fs &&...fs) { constexpr const size_t size = sizeof...(Fs); static_assert(size != 0 || size != 2); if constexpr (size == 2) { @@ -333,7 +334,8 @@ private: #else static_assert( !is_ssl_, - "please add definition CINATRA_ENABLE_SSL"); // guard, not allowed coming in this branch + "please add definition CINATRA_ENABLE_SSL"); // guard, not allowed + // coming in this branch #endif } @@ -393,7 +395,10 @@ private: return; } } - // if (req_.get_method() == "GET"&&http_cache::get().need_cache(req_.get_url())&&!http_cache::get().not_cache(req_.get_url())) { handle_cache(); return; + // if (req_.get_method() == + //"GET"&&http_cache::get().need_cache(req_.get_url())&&!http_cache::get().not_cache(req_.get_url())) + //{ handle_cache(); + //return; // } req_.set_last_len(len_); @@ -465,7 +470,8 @@ private: size_t left_body_len = 0; // int index = 1; while (true) { - // std::cout << std::this_thread::get_id() << ", index: " << index << "\n"; + // std::cout << std::this_thread::get_id() << ", index: " << index << + // "\n"; result = req_.parse_header(len_); if (result == -1) { return; @@ -571,7 +577,11 @@ private: } // cache - // if (req_.get_method() == "GET"&&http_cache::get().need_cache(req_.get_url()) && !http_cache::get().not_cache(req_.get_url())) { auto raw_url = req_.raw_url(); http_cache::get().add(std::string(raw_url.data(), raw_url.length()), res_.raw_content()); + // if (req_.get_method() == + //"GET"&&http_cache::get().need_cache(req_.get_url()) && + //!http_cache::get().not_cache(req_.get_url())) { auto raw_url = + //req_.raw_url(); http_cache::get().add(std::string(raw_url.data(), + //raw_url.length()), res_.raw_content()); // } boost::asio::async_write( @@ -648,7 +658,8 @@ private: /****************** begin handle http body data *****************/ void handle_string_body(std::size_t bytes_transferred) { - // defalt add limitation for string_body and else. you can remove the limitation for very big string. + // defalt add limitation for string_body and else. you can remove the + // limitation for very big string. if (req_.at_capacity()) { response_back(status_type::bad_request, "The request is too long, limitation is 3M"); @@ -1191,7 +1202,8 @@ private: } //-------------web socket----------------// - //-------------chunked(read chunked not support yet, write chunked is ok)----------------------// + //-------------chunked(read chunked not support yet, write chunked is + //ok)----------------------// void handle_chunked(size_t bytes_transferred) { int ret = req_.parse_chunked(bytes_transferred); if (ret == parse_status::has_error) { @@ -1208,7 +1220,8 @@ private: req_.set_state(data_proc_state::data_continue); call_back(); // app set the data } - //-------------chunked(read chunked not support yet, write chunked is ok)----------------------// + //-------------chunked(read chunked not support yet, write chunked is + //ok)----------------------// void handle_body() { if (req_.at_capacity()) { @@ -1398,4 +1411,4 @@ inline constexpr data_proc_state ws_open = data_proc_state::data_begin; inline constexpr data_proc_state ws_message = data_proc_state::data_continue; inline constexpr data_proc_state ws_close = data_proc_state::data_close; inline constexpr data_proc_state ws_error = data_proc_state::data_error; -} +} // namespace cinatra diff --git a/include/cinatra/cookie.hpp b/include/cinatra/cookie.hpp index 6acd849..e02d63d 100644 --- a/include/cinatra/cookie.hpp +++ b/include/cinatra/cookie.hpp @@ -1,150 +1,111 @@ #pragma once -#include #include "utils.hpp" +#include namespace cinatra { - class cookie { - public: - cookie() = default; - cookie(const std::string& name, const std::string& value) : name_(name), value_(value) { - - } - - void set_version(int version) { - version_ = version; - } - - void set_name(const std::string& name) { - name_ = name; - } - - std::string get_name() const { - return name_; - } - - void set_value(const std::string& value) { - value_ = value; - } - - std::string get_value() const { - return value_; - } - - void set_comment(const std::string& comment) { - comment_ = comment; - } - - void set_domain(const std::string& domain) { - domain_ = domain; - } - - void set_path(const std::string& path) { - path_ = path; - } - - void set_priority(const std::string& priority) { - priority_ = priority; - } - - void set_secure(bool secure) { - secure_ = secure; - } - - void set_max_age(std::time_t seconds) { - max_age_ = seconds; - } - - void set_http_only(bool http_only) { - http_only_ = http_only; - } - - std::string to_string() const { - std::string result; - result.reserve(256); - result.append(name_); - result.append("="); - if (version_ == 0) - { - // Netscape cookie - result.append(value_); - if (!path_.empty()) - { - result.append("; path="); - result.append(path_); - } - if (!priority_.empty()) - { - result.append("; Priority="); - result.append(priority_); - } - if (max_age_ != -1) - { - result.append("; expires="); - result.append(get_gmt_time_str(max_age_)); - } - if (secure_) - { - result.append("; secure"); - } - if (http_only_) - { - result.append("; HttpOnly"); - } - } - else - { - // RFC 2109 cookie - result.append("\""); - result.append(value_); - result.append("\""); - if (!comment_.empty()) - { - result.append("; Comment=\""); - result.append(comment_); - result.append("\""); - } - if (!path_.empty()) - { - result.append("; Path=\""); - result.append(path_); - result.append("\""); - } - if (!priority_.empty()) - { - result.append("; Priority=\""); - result.append(priority_); - result.append("\""); - } - - if (max_age_ != -1) - { - result.append("; Max-Age=\""); - result.append(std::to_string(max_age_)); - result.append("\""); - } - if (secure_) - { - result.append("; secure"); - } - if (http_only_) - { - result.append("; HttpOnly"); - } - result.append("; Version=\"1\""); - } - return result; - } - - private: - int version_ = 0; - std::string name_ = ""; - std::string value_ = ""; - std::string comment_ = ""; - std::string domain_ = ""; - std::string path_ = ""; - std::string priority_ = ""; - bool secure_ = false; - std::time_t max_age_ = -1; - bool http_only_ = false; - }; -} +class cookie { +public: + cookie() = default; + cookie(const std::string &name, const std::string &value) + : name_(name), value_(value) {} + + void set_version(int version) { version_ = version; } + + void set_name(const std::string &name) { name_ = name; } + + std::string get_name() const { return name_; } + + void set_value(const std::string &value) { value_ = value; } + + std::string get_value() const { return value_; } + + void set_comment(const std::string &comment) { comment_ = comment; } + + void set_domain(const std::string &domain) { domain_ = domain; } + + void set_path(const std::string &path) { path_ = path; } + + void set_priority(const std::string &priority) { priority_ = priority; } + + void set_secure(bool secure) { secure_ = secure; } + + void set_max_age(std::time_t seconds) { max_age_ = seconds; } + + void set_http_only(bool http_only) { http_only_ = http_only; } + + std::string to_string() const { + std::string result; + result.reserve(256); + result.append(name_); + result.append("="); + if (version_ == 0) { + // Netscape cookie + result.append(value_); + if (!path_.empty()) { + result.append("; path="); + result.append(path_); + } + if (!priority_.empty()) { + result.append("; Priority="); + result.append(priority_); + } + if (max_age_ != -1) { + result.append("; expires="); + result.append(get_gmt_time_str(max_age_)); + } + if (secure_) { + result.append("; secure"); + } + if (http_only_) { + result.append("; HttpOnly"); + } + } else { + // RFC 2109 cookie + result.append("\""); + result.append(value_); + result.append("\""); + if (!comment_.empty()) { + result.append("; Comment=\""); + result.append(comment_); + result.append("\""); + } + if (!path_.empty()) { + result.append("; Path=\""); + result.append(path_); + result.append("\""); + } + if (!priority_.empty()) { + result.append("; Priority=\""); + result.append(priority_); + result.append("\""); + } + + if (max_age_ != -1) { + result.append("; Max-Age=\""); + result.append(std::to_string(max_age_)); + result.append("\""); + } + if (secure_) { + result.append("; secure"); + } + if (http_only_) { + result.append("; HttpOnly"); + } + result.append("; Version=\"1\""); + } + return result; + } + +private: + int version_ = 0; + std::string name_ = ""; + std::string value_ = ""; + std::string comment_ = ""; + std::string domain_ = ""; + std::string path_ = ""; + std::string priority_ = ""; + bool secure_ = false; + std::time_t max_age_ = -1; + bool http_only_ = false; +}; +} // namespace cinatra diff --git a/include/cinatra/define.h b/include/cinatra/define.h index 1314bd7..f76ef16 100644 --- a/include/cinatra/define.h +++ b/include/cinatra/define.h @@ -1,5 +1,5 @@ #pragma once -#if defined (__GNUC__) +#if defined(__GNUC__) #if __GNUC__ < 8 #include namespace fs = std::experimental::filesystem; @@ -13,37 +13,32 @@ namespace fs = std::filesystem; #endif namespace cinatra { - enum class content_type { - string, - multipart, - urlencoded, - chunked, - octet_stream, - websocket, - unknown, - }; +enum class content_type { + string, + multipart, + urlencoded, + chunked, + octet_stream, + websocket, + unknown, +}; - enum class req_content_type{ - html, - json, - string, - multipart, - none - }; +enum class req_content_type { html, json, string, multipart, none }; - constexpr inline auto HTML = req_content_type::html; - constexpr inline auto JSON = req_content_type::json; - constexpr inline auto TEXT = req_content_type::string; - constexpr inline auto NONE = req_content_type::none; +constexpr inline auto HTML = req_content_type::html; +constexpr inline auto JSON = req_content_type::json; +constexpr inline auto TEXT = req_content_type::string; +constexpr inline auto NONE = req_content_type::none; - inline const std::string_view STATIC_RESOURCE = "cinatra_static_resource"; - inline const std::string CSESSIONID = "CSESSIONID"; +inline const std::string_view STATIC_RESOURCE = "cinatra_static_resource"; +inline const std::string CSESSIONID = "CSESSIONID"; - const static inline std::string CRCF = "\r\n"; - const static inline std::string TWO_CRCF = "\r\n\r\n"; - const static inline std::string BOUNDARY = "--CinatraBoundary2B8FAF4A80EDB307"; - const static inline std::string MULTIPART_END = CRCF + "--" + BOUNDARY + "--" + TWO_CRCF; +const static inline std::string CRCF = "\r\n"; +const static inline std::string TWO_CRCF = "\r\n\r\n"; +const static inline std::string BOUNDARY = "--CinatraBoundary2B8FAF4A80EDB307"; +const static inline std::string MULTIPART_END = + CRCF + "--" + BOUNDARY + "--" + TWO_CRCF; - struct NonSSL {}; - struct SSL {}; -} +struct NonSSL {}; +struct SSL {}; +} // namespace cinatra diff --git a/include/cinatra/dh1024.pem b/include/cinatra/dh1024.pem index c0defe4..b537564 100644 --- a/include/cinatra/dh1024.pem +++ b/include/cinatra/dh1024.pem @@ -1,5 +1,6 @@ ------BEGIN DH PARAMETERS----- -MIGHAoGBAKkQmvrDWq/HYZy8tkXIEOHb1EnViMz+hLmjx64Bv4QF+B6e3dXjbUf5 -gzlvFMFs1bY35XA3oRW//Qp5Jkj9Mz+VM/FYuZr8MYJosxIRlAPSVYQs6W4FqwK8 -MhezkO2Pt6KhKrUUO7IjLY84pmoo9d8f+DLZi9opBdEKBX6Qd28LAgEC ------END DH PARAMETERS----- +-----BEGIN DH PARAMETERS-- ---MIGHAoGBAKkQmvrDWq / HYZy8tkXIEOHb1EnViMz + + hLmjx64Bv4QF + + B6e3dXjbUf5 + gzlvFMFs1bY35XA3oRW // Qp5Jkj9Mz+VM/FYuZr8MYJosxIRlAPSVYQs6W4FqwK8 + MhezkO2Pt6KhKrUUO7IjLY84pmoo9d8f + + DLZi9opBdEKBX6Qd28LAgEC-- ---END DH PARAMETERS-- --- diff --git a/include/cinatra/function_traits.hpp b/include/cinatra/function_traits.hpp index 758fbd4..3264e82 100644 --- a/include/cinatra/function_traits.hpp +++ b/include/cinatra/function_traits.hpp @@ -1,88 +1,94 @@ #pragma once -#include #include #include +#include -//member function -#define TIMAX_FUNCTION_TRAITS(...)\ -template \ -struct function_traits_impl : function_traits_impl{};\ +// member function +#define TIMAX_FUNCTION_TRAITS(...) \ + template \ + struct function_traits_impl \ + : function_traits_impl {}; -namespace timax -{ - /* - * 1. function type ==> Ret(Args...) - * 2. function pointer ==> Ret(*)(Args...) - * 3. function reference ==> Ret(&)(Args...) - * 4. pointer to non-static member function ==> Ret(T::*)(Args...) - * 5. function object and functor ==> &T::operator() - * 6. function with generic operator call ==> template &T::operator() - */ - template - struct function_traits_impl; +namespace timax { +/* + * 1. function type ==> + * Ret(Args...) + * 2. function pointer ==> + * Ret(*)(Args...) + * 3. function reference ==> + * Ret(&)(Args...) + * 4. pointer to non-static member function ==> Ret(T::*)(Args...) + * 5. function object and functor ==> &T::operator() + * 6. function with generic operator call ==> template &T::operator() + */ +template struct function_traits_impl; - template - struct function_traits : function_traits_impl< - std::remove_cv_t>> - {}; +template +struct function_traits + : function_traits_impl>> {}; - template - struct function_traits_impl - { - public: - enum { arity = sizeof...(Args) }; - typedef Ret function_type(Args...); - typedef Ret result_type; - using stl_function_type = std::function; - typedef Ret(*pointer)(Args...); +template +struct function_traits_impl { +public: + enum { arity = sizeof...(Args) }; + typedef Ret function_type(Args...); + typedef Ret result_type; + using stl_function_type = std::function; + typedef Ret (*pointer)(Args...); - template - struct args - { - static_assert(I < arity, "index is out of range, index must less than sizeof Args"); - using type = typename std::tuple_element>::type; - }; + template struct args { + static_assert(I < arity, + "index is out of range, index must less than sizeof Args"); + using type = typename std::tuple_element>::type; + }; - typedef std::tuple>...> tuple_type; - using args_type_t = std::tuple; - }; + typedef std::tuple>...> + tuple_type; + using args_type_t = std::tuple; +}; - template - using arg_type = typename function_traits::template args::type; +template +using arg_type = typename function_traits::template args::type; - // function pointer - template - struct function_traits_impl : function_traits {}; +// function pointer +template +struct function_traits_impl : function_traits { +}; - // std::function - template - struct function_traits_impl> : function_traits_impl {}; +// std::function +template +struct function_traits_impl> + : function_traits_impl {}; - // pointer of non-static member function - TIMAX_FUNCTION_TRAITS() - TIMAX_FUNCTION_TRAITS(const) - TIMAX_FUNCTION_TRAITS(volatile) - TIMAX_FUNCTION_TRAITS(const volatile) +// pointer of non-static member function +TIMAX_FUNCTION_TRAITS() +TIMAX_FUNCTION_TRAITS(const) +TIMAX_FUNCTION_TRAITS(volatile) +TIMAX_FUNCTION_TRAITS(const volatile) - // functor - template - struct function_traits_impl : function_traits_impl {}; +// functor +template +struct function_traits_impl + : function_traits_impl {}; - template - typename function_traits::stl_function_type to_function(const Function& lambda) - { - return static_cast::stl_function_type>(lambda); - } +template +typename function_traits::stl_function_type +to_function(const Function &lambda) { + return static_cast::stl_function_type>( + lambda); +} - template - typename function_traits::stl_function_type to_function(Function&& lambda) - { - return static_cast::stl_function_type>(std::forward(lambda)); - } +template +typename function_traits::stl_function_type +to_function(Function &&lambda) { + return static_cast::stl_function_type>( + std::forward(lambda)); +} - template - typename function_traits::pointer to_function_pointer(const Function& lambda) - { - return static_cast::pointer>(lambda); - } +template +typename function_traits::pointer +to_function_pointer(const Function &lambda) { + return static_cast::pointer>(lambda); } +} // namespace timax diff --git a/include/cinatra/gzip.hpp b/include/cinatra/gzip.hpp index a7e8e1a..d749103 100644 --- a/include/cinatra/gzip.hpp +++ b/include/cinatra/gzip.hpp @@ -1,148 +1,142 @@ #pragma once -#include #include +#include namespace cinatra::gzip_codec { - //from https://github.com/chafey/GZipCodec +// from https://github.com/chafey/GZipCodec #define CHUNK 16384 #define windowBits 15 #define GZIP_ENCODING 16 - // GZip Compression - // @param data - the data to compress (does not have to be string, can be binary data) - // @param compressed_data - the resulting gzip compressed data - // @param level - the gzip compress level -1 = default, 0 = no compression, 1= worst/fastest compression, 9 = best/slowest compression - // @return - true on success, false on failure - inline bool compress(std::string_view data, std::string& compressed_data, int level = -1) { - unsigned char out[CHUNK]; - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - if (deflateInit2(&strm, level, Z_DEFLATED, windowBits | GZIP_ENCODING, 8, Z_DEFAULT_STRATEGY) != Z_OK) - { - return false; - } - strm.next_in = (unsigned char*)data.data(); - strm.avail_in = (uInt)data.length(); - do { - int have; - strm.avail_out = CHUNK; - strm.next_out = out; - if (deflate(&strm, Z_FINISH) == Z_STREAM_ERROR) - { - return false; - } - have = CHUNK - strm.avail_out; - compressed_data.append((char*)out, have); - } while (strm.avail_out == 0); - if (deflateEnd(&strm) != Z_OK) - { - return false; - } - return true; - } +// GZip Compression +// @param data - the data to compress (does not have to be string, can be binary +// data) +// @param compressed_data - the resulting gzip compressed data +// @param level - the gzip compress level -1 = default, 0 = no compression, 1= +// worst/fastest compression, 9 = best/slowest compression +// @return - true on success, false on failure +inline bool compress(std::string_view data, std::string &compressed_data, + int level = -1) { + unsigned char out[CHUNK]; + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + if (deflateInit2(&strm, level, Z_DEFLATED, windowBits | GZIP_ENCODING, 8, + Z_DEFAULT_STRATEGY) != Z_OK) { + return false; + } + strm.next_in = (unsigned char *)data.data(); + strm.avail_in = (uInt)data.length(); + do { + int have; + strm.avail_out = CHUNK; + strm.next_out = out; + if (deflate(&strm, Z_FINISH) == Z_STREAM_ERROR) { + return false; + } + have = CHUNK - strm.avail_out; + compressed_data.append((char *)out, have); + } while (strm.avail_out == 0); + if (deflateEnd(&strm) != Z_OK) { + return false; + } + return true; +} - // GZip Decompression - // @param compressed_data - the gzip compressed data - // @param data - the resulting uncompressed data (may contain binary data) - // @return - true on success, false on failure - inline bool uncompress(std::string_view compressed_data, std::string& data) { - int ret; - unsigned have; - z_stream strm; - unsigned char out[CHUNK]; +// GZip Decompression +// @param compressed_data - the gzip compressed data +// @param data - the resulting uncompressed data (may contain binary data) +// @return - true on success, false on failure +inline bool uncompress(std::string_view compressed_data, std::string &data) { + int ret; + unsigned have; + z_stream strm; + unsigned char out[CHUNK]; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - if (inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK) - { - return false; - } + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + if (inflateInit2(&strm, 16 + MAX_WBITS) != Z_OK) { + return false; + } - strm.avail_in = (uInt)compressed_data.length(); - strm.next_in = (unsigned char*)compressed_data.data(); - do { - strm.avail_out = CHUNK; - strm.next_out = out; - ret = inflate(&strm, Z_NO_FLUSH); - switch (ret) { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&strm); - return false; - } - have = CHUNK - strm.avail_out; - data.append((char*)out, have); - } while (strm.avail_out == 0); + strm.avail_in = (uInt)compressed_data.length(); + strm.next_in = (unsigned char *)compressed_data.data(); + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + return false; + } + have = CHUNK - strm.avail_out; + data.append((char *)out, have); + } while (strm.avail_out == 0); - if (inflateEnd(&strm) != Z_OK) { - return false; - } + if (inflateEnd(&strm) != Z_OK) { + return false; + } - return true; - } + return true; +} - inline int compress_file(const char* src_file, const char * out_file_name) - { - char buf[BUFSIZ] = { 0 }; - uInt bytes_read = 0; - gzFile out = gzopen(out_file_name, "wb"); - if (!out) - { - return -1; - } +inline int compress_file(const char *src_file, const char *out_file_name) { + char buf[BUFSIZ] = {0}; + uInt bytes_read = 0; + gzFile out = gzopen(out_file_name, "wb"); + if (!out) { + return -1; + } - std::ifstream in(src_file, std::ios::binary); - if (!in.is_open()) { - return -1; - } + std::ifstream in(src_file, std::ios::binary); + if (!in.is_open()) { + return -1; + } - while (true) - { - in.read(buf, BUFSIZ); - bytes_read = (uInt)in.gcount(); - if (bytes_read == 0) - break; - int bytes_written = gzwrite(out, buf, bytes_read); - if (bytes_written == 0) - { - gzclose(out); - return -1; - } - if (bytes_read != BUFSIZ) - break; - } - gzclose(out); + while (true) { + in.read(buf, BUFSIZ); + bytes_read = (uInt)in.gcount(); + if (bytes_read == 0) + break; + int bytes_written = gzwrite(out, buf, bytes_read); + if (bytes_written == 0) { + gzclose(out); + return -1; + } + if (bytes_read != BUFSIZ) + break; + } + gzclose(out); - return 0; - } + return 0; +} - inline int uncompress_file(const char* src_file, const char * out_file_name) { - char buf[BUFSIZ] = { 0 }; - std::ofstream out(out_file_name, std::ios::binary); - if (!out.is_open()) { - return -1; - } +inline int uncompress_file(const char *src_file, const char *out_file_name) { + char buf[BUFSIZ] = {0}; + std::ofstream out(out_file_name, std::ios::binary); + if (!out.is_open()) { + return -1; + } - gzFile fi = gzopen(src_file, "rb"); - if (!fi) - { - return -1; - } + gzFile fi = gzopen(src_file, "rb"); + if (!fi) { + return -1; + } - gzrewind(fi); - while (!gzeof(fi)) - { - int len = gzread(fi, buf, BUFSIZ); - out.write(buf, len); - } - gzclose(fi); + gzrewind(fi); + while (!gzeof(fi)) { + int len = gzread(fi, buf, BUFSIZ); + out.write(buf, len); + } + gzclose(fi); - return 0; - } -} \ No newline at end of file + return 0; +} +} // namespace cinatra::gzip_codec \ No newline at end of file diff --git a/include/cinatra/http_cache.hpp b/include/cinatra/http_cache.hpp index 9450602..717eb78 100644 --- a/include/cinatra/http_cache.hpp +++ b/include/cinatra/http_cache.hpp @@ -1,105 +1,93 @@ #pragma once +#include "use_asio.hpp" +#include #include #include -#include #include #include #include -#include "use_asio.hpp" namespace cinatra { - constexpr const size_t MAX_CACHE_SIZE = 100000; - - class http_cache { - public: - static http_cache& get(){ - static http_cache instance; - return instance; - } - - void add(const std::string& key, const std::vector& content) { - std::unique_lock lock(mtx_); - - if (std::distance(cur_it_, cache_.end()) > MAX_CACHE_SIZE) { - cur_it_ = cache_.begin(); - } - - cur_it_ = cache_.emplace(key, content).first; - cache_time_[key] = std::time(nullptr) + max_cache_age_; - } - - std::vector get(const std::string& key) { - std::unique_lock lock(mtx_); - auto time_it = cache_time_.find(key); - auto it = cache_.find(key); - auto now_time = std::time(nullptr); - if(time_it != cache_time_.end() && time_it->second >= now_time){ - return it == cache_.end() ? std::vector{} : it->second; - }else{ - if(time_it != cache_time_.end() && it != cache_.end()){ - cur_it_ = cache_.erase(it); - } - return std::vector{}; - } - } - - bool empty() { - return cache_.empty(); - } - - void update(const std::string& key) { - std::unique_lock lock(mtx_); - auto it = cache_.find(key); - if (it != cache_.end()) - cache_.erase(it); - } - - void add_skip(std::string_view key) { - skip_cache_.emplace(key); - } - - void add_single_cache(std::string_view key) - { - need_single_cache_.emplace(key); - } - - void enable_cache(bool b) { - need_cache_ = b; - } - - bool need_cache(std::string_view key) { - if(need_cache_){ - return need_cache_; - }else{ - return need_single_cache_.find(key)!= need_single_cache_.end(); - } - } - - bool not_cache(std::string_view key) { - return skip_cache_.find(key) != skip_cache_.end(); - } - - void set_cache_max_age(std::time_t seconds) - { - max_cache_age_ = seconds; - } - - std::time_t get_cache_max_age() - { - return max_cache_age_; - } - - private: - http_cache() {}; - http_cache(const http_cache&) = delete; - http_cache(http_cache&&) = delete; - - std::mutex mtx_; - bool need_cache_ = false; - std::unordered_map> cache_; - std::unordered_map>::iterator cur_it_ = http_cache::cache_.begin(); - std::unordered_set skip_cache_; - std::unordered_set need_single_cache_; - std::time_t max_cache_age_ = 0; - std::unordered_map cache_time_; - }; -} \ No newline at end of file +constexpr const size_t MAX_CACHE_SIZE = 100000; + +class http_cache { +public: + static http_cache &get() { + static http_cache instance; + return instance; + } + + void add(const std::string &key, const std::vector &content) { + std::unique_lock lock(mtx_); + + if (std::distance(cur_it_, cache_.end()) > MAX_CACHE_SIZE) { + cur_it_ = cache_.begin(); + } + + cur_it_ = cache_.emplace(key, content).first; + cache_time_[key] = std::time(nullptr) + max_cache_age_; + } + + std::vector get(const std::string &key) { + std::unique_lock lock(mtx_); + auto time_it = cache_time_.find(key); + auto it = cache_.find(key); + auto now_time = std::time(nullptr); + if (time_it != cache_time_.end() && time_it->second >= now_time) { + return it == cache_.end() ? std::vector{} : it->second; + } else { + if (time_it != cache_time_.end() && it != cache_.end()) { + cur_it_ = cache_.erase(it); + } + return std::vector{}; + } + } + + bool empty() { return cache_.empty(); } + + void update(const std::string &key) { + std::unique_lock lock(mtx_); + auto it = cache_.find(key); + if (it != cache_.end()) + cache_.erase(it); + } + + void add_skip(std::string_view key) { skip_cache_.emplace(key); } + + void add_single_cache(std::string_view key) { + need_single_cache_.emplace(key); + } + + void enable_cache(bool b) { need_cache_ = b; } + + bool need_cache(std::string_view key) { + if (need_cache_) { + return need_cache_; + } else { + return need_single_cache_.find(key) != need_single_cache_.end(); + } + } + + bool not_cache(std::string_view key) { + return skip_cache_.find(key) != skip_cache_.end(); + } + + void set_cache_max_age(std::time_t seconds) { max_cache_age_ = seconds; } + + std::time_t get_cache_max_age() { return max_cache_age_; } + +private: + http_cache(){}; + http_cache(const http_cache &) = delete; + http_cache(http_cache &&) = delete; + + std::mutex mtx_; + bool need_cache_ = false; + std::unordered_map> cache_; + std::unordered_map>::iterator cur_it_ = + http_cache::cache_.begin(); + std::unordered_set skip_cache_; + std::unordered_set need_single_cache_; + std::time_t max_cache_age_ = 0; + std::unordered_map cache_time_; +}; +} // namespace cinatra \ No newline at end of file diff --git a/include/cinatra/http_client.hpp b/include/cinatra/http_client.hpp index 1d3d59d..111d41f 100644 --- a/include/cinatra/http_client.hpp +++ b/include/cinatra/http_client.hpp @@ -1,18 +1,18 @@ #pragma once -#include -#include -#include -#include +#include "http_parser.hpp" +#include "itoa_jeaiii.hpp" +#include "modern_callback.h" +#include "uri.hpp" +#include "use_asio.hpp" #include +#include #include +#include #include -#include +#include #include -#include "use_asio.hpp" -#include "uri.hpp" -#include "http_parser.hpp" -#include "itoa_jeaiii.hpp" -#include "modern_callback.h" +#include +#include #ifdef CINATRA_ENABLE_SSL #ifdef ASIO_STANDALONE @@ -23,1022 +23,1137 @@ #endif namespace cinatra { - struct response_data { - boost::system::error_code ec; - int status; - std::string_view resp_body; - std::pair resp_headers; - }; - using callback_t = std::function; - - inline static std::string INVALID_URI = "invalid_uri"; - inline static std::string REQUEST_TIMEOUT = "request timeout"; - inline static std::string MULTIPLE_REQUEST = "last async request not finished"; - inline static std::string METHOD_ERROR = "method error"; - inline static std::string INVALID_FILE_PATH = "invalid file path"; - inline static std::string OPEN_FAILED = "open file failed"; - inline static std::string FILE_SIZE_ERROR = "filesize error"; - inline static std::string RESP_PARSE_ERROR = "http response parse error"; - inline static std::string INVALID_CHUNK_SIZE = "invalid chunk size"; - inline static std::string READ_TIMEOUT = "read timeout"; - - class http_client : public std::enable_shared_from_this { - public: - http_client(boost::asio::io_service& ios) : - ios_(ios), resolver_(ios), socket_(ios), timer_(ios) { - future_ = read_close_finished_.get_future(); - } - - ~http_client() { - close(); - } - - response_data get(std::string uri) { - return request(http_method::GET, std::move(uri), req_content_type::json, timeout_seconds_); - } - - response_data get(std::string uri, size_t seconds) { - return request(http_method::GET, std::move(uri), req_content_type::json, seconds); - } - - response_data get(std::string uri, req_content_type type) { - return request(http_method::GET, std::move(uri), type, timeout_seconds_); - } - - response_data get(std::string uri, size_t seconds, req_content_type type) { - return request(http_method::GET, std::move(uri), type, seconds); - } - - response_data get(std::string uri, req_content_type type, size_t seconds) { - return request(http_method::GET, std::move(uri), type, seconds); - } - - response_data post(std::string uri, std::string body) { - return request(http_method::POST, std::move(uri), req_content_type::json, timeout_seconds_, std::move(body)); - } - - response_data post(std::string uri, std::string body, req_content_type type) { - return request(http_method::POST, std::move(uri), type, timeout_seconds_, std::move(body)); - } - - response_data post(std::string uri, std::string body, size_t seconds) { - return request(http_method::POST, std::move(uri), req_content_type::json, seconds, std::move(body)); - } - - response_data post(std::string uri, std::string body, req_content_type type, size_t seconds) { - return request(http_method::POST, std::move(uri), type, seconds, std::move(body)); - } - - response_data post(std::string uri, std::string body, size_t seconds, req_content_type type) { - return request(http_method::POST, std::move(uri), type, seconds, std::move(body)); - } - - response_data request(http_method method, std::string uri, req_content_type type = req_content_type::json, size_t seconds = 15, std::string body = "") { - promise_ = std::make_shared>(); - sync_ = true; - if (!chunked_result_.empty()) { - chunked_result_.clear(); - } - - async_request(method, std::move(uri), nullptr, type, seconds, std::move(body)); - auto future = promise_->get_future(); - auto status = future.wait_for(std::chrono::seconds(seconds)); - in_progress_ = false; - if (status == std::future_status::timeout) { - promise_ = nullptr; - return { boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), 404, REQUEST_TIMEOUT }; - } - auto result = future.get(); - promise_ = nullptr; - return result; - } - - template - auto async_get(std::string uri, _Callback&& cb) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), req_content_type::json, timeout_seconds_); - } - - template - auto async_get(std::string uri, req_content_type type, _Callback&& cb) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), type, timeout_seconds_); - } - - template - auto async_get(std::string uri, _Callback&& cb, req_content_type type) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), type, timeout_seconds_); - } - - template - auto async_get(std::string uri, _Callback&& cb, size_t seconds) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), req_content_type::json, seconds); - } - - template - auto async_get(std::string uri, _Callback&& cb, req_content_type type, size_t seconds) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), type, seconds); - } - - template - auto async_get(std::string uri, _Callback&& cb, size_t seconds, req_content_type type) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), type, seconds); - } - - template - auto async_get(std::string uri, size_t seconds, _Callback&& cb) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), req_content_type::json, seconds); - } - - template - auto async_get(std::string uri, req_content_type type, size_t seconds, _Callback&& cb) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), type, seconds); - } - - template - auto async_get(std::string uri, size_t seconds, req_content_type type, _Callback&& cb) { - return async_request(http_method::GET, std::move(uri), std::forward<_Callback>(cb), type, seconds); - } - - template - auto async_post(std::string uri, std::string body, _Callback&& cb) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), req_content_type::json, timeout_seconds_, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, _Callback&& cb, req_content_type type) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), type, timeout_seconds_, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, _Callback&& cb, size_t seconds) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), req_content_type::json, seconds, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, _Callback&& cb, req_content_type type, size_t seconds) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), type, seconds, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, _Callback&& cb, size_t seconds, req_content_type type) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), type, seconds, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, req_content_type type, _Callback&& cb) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), type, timeout_seconds_, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, size_t seconds, _Callback&& cb) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), req_content_type::json, seconds, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, req_content_type type, size_t seconds, _Callback&& cb) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), type, seconds, std::move(body)); - } - - template - auto async_post(std::string uri, std::string body, size_t seconds, req_content_type type, _Callback&& cb) { - return async_request(http_method::POST, std::move(uri), std::forward<_Callback>(cb), type, seconds, std::move(body)); - } - - template - auto async_request(http_method method, std::string uri, _Callable_t&& cb, req_content_type type = req_content_type::json, size_t seconds = 15, std::string body = "") - ->MODERN_CALLBACK_RESULT(void(response_data)){ - MODERN_CALLBACK_TRAITS(cb, void(response_data)); - async_request_impl(method, std::move(uri), MODERN_CALLBACK_CALL(), type, seconds, std::move(body)); - MODERN_CALLBACK_RETURN(); - } - void async_request_impl(http_method method, std::string uri, callback_t cb, req_content_type type = req_content_type::json, size_t seconds = 15, std::string body = "") { - bool need_switch = false; - if (!promise_) {//just for async request, guard continuous async request, it's not allowed; async request must be after last one finished! - need_switch = sync_; - sync_ = false; - } - - if (in_progress_) { - set_error_value(cb, boost::asio::error::basic_errors::in_progress, MULTIPLE_REQUEST); - return; - } - else { - in_progress_ = true; - } - - if (method != http_method::POST && !body.empty()) { - set_error_value(cb, boost::asio::error::basic_errors::invalid_argument, METHOD_ERROR); - return; - } - - bool init = last_domain_.empty(); - bool need_reset = need_switch || (!init && (uri.find(last_domain_) == std::string::npos)); - - if (need_reset) { - close(false); - - //wait for read close finish - future_.wait(); - read_close_finished_ = {}; - future_ = read_close_finished_.get_future(); - - reset_socket(); - } - - auto [r, u] = get_uri(uri); - if (!r) { - set_error_value(cb, boost::asio::error::basic_errors::invalid_argument, INVALID_URI); - return; - } - - last_domain_ = std::string(u.schema).append("://").append(u.host); - timeout_seconds_ = seconds; - req_content_type_ = type; - cb_ = std::move(cb); - context ctx(u, method, std::move(body)); - if (promise_) { - weak_ = promise_; - } - if (has_connected_) { - do_write(std::move(ctx)); - } - else { - async_connect(std::move(ctx)); - } - } - - template - auto download(std::string src_file, std::string dest_file, _Callable_t&& cb, size_t seconds = 60) { - return download(std::move(src_file), std::move(dest_file), 0, std::move(cb), seconds); - } - - template - auto download(std::string src_file, std::string dest_file, int64_t size, _Callable_t&& cb, size_t seconds = 60) - ->MODERN_CALLBACK_RESULT(void(response_data)) { - MODERN_CALLBACK_TRAITS(cb, void(response_data)); - download_impl(std::move(src_file), std::move(dest_file), size, MODERN_CALLBACK_CALL(), seconds); - MODERN_CALLBACK_RETURN(); - } - - void download_impl(std::string src_file, std::string dest_file, int64_t size, callback_t cb, size_t seconds = 60) { - auto parant_path = fs::path(dest_file).parent_path(); - std::error_code code; - fs::create_directories(parant_path, code); - if (code) { - cb_ = std::move(cb); - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), INVALID_FILE_PATH); - return; - } - - if (size > 0) { - char buffer[20]; - auto p = i64toa_jeaiii(size, buffer); - add_header("cinatra_start_pos", std::string(buffer, p - buffer)); - } - else { - int64_t file_size = fs::file_size(dest_file, code); - if (!code && file_size > 0) { - char buffer[20]; - auto p = i64toa_jeaiii(file_size, buffer); - add_header("cinatra_start_pos", std::string(buffer, p - buffer)); - } - } - - download_file_ = std::make_shared(dest_file, std::ios::binary | std::ios::app); - if (!download_file_->is_open()) { - cb_ = std::move(cb); - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), OPEN_FAILED); - return; - } - - if (size > 0) { - char buffer[20]; - auto p = i64toa_jeaiii(size, buffer); - add_header("cinatra_start_pos", std::string(buffer, p - buffer)); - } - else { - int64_t file_size = fs::file_size(dest_file, code); - if (!code && file_size > 0) { - char buffer[20]; - auto p = i64toa_jeaiii(file_size, buffer); - add_header("cinatra_start_pos", std::string(buffer, p - buffer)); - } - } - - async_get(std::move(src_file), std::move(cb), req_content_type::none, seconds); - } - - void download(std::string src_file, std::function chunk, size_t seconds = 60) { - on_chunk_ = std::move(chunk); - async_get(std::move(src_file), nullptr, req_content_type::none, seconds); - } - - template - auto upload(std::string uri, std::string filename, _Callable_t&& cb, size_t seconds = 60) { - return upload(std::move(uri), std::move(filename), 0, std::forward<_Callable_t>(cb), seconds); - } - - template - auto upload(std::string uri, std::string filename, size_t start, _Callable_t&& cb, size_t seconds = 60) { - multipart_str_ = std::move(filename); - start_ = start; - return async_request(http_method::POST, uri, std::forward<_Callable_t>(cb), req_content_type::multipart, seconds, ""); - } - - void add_header(std::string key, std::string val) { - if (key.empty()) - return; - - if (key == "Host") - return; - - headers_.emplace_back(std::move(key), std::move(val)); - } - - void add_header_str(std::string pair_str) { - if (pair_str.empty()) - return; - - if (pair_str.find("Host:") != std::string::npos) - return; - - header_str_.append(pair_str); - } - - void clear_headers() { - if (!headers_.empty()) { - headers_.clear(); - } - - if (!header_str_.empty()) { - header_str_.clear(); - } - } - - std::pair get_resp_headers() { - if (!copy_headers_.empty()) - parser_.set_headers(copy_headers_); - - return parser_.get_headers(); - } - - std::string_view get_header_value(std::string_view key) { - return parser_.get_header_value(key); - } +struct response_data { + boost::system::error_code ec; + int status; + std::string_view resp_body; + std::pair resp_headers; +}; +using callback_t = std::function; + +inline static std::string INVALID_URI = "invalid_uri"; +inline static std::string REQUEST_TIMEOUT = "request timeout"; +inline static std::string MULTIPLE_REQUEST = "last async request not finished"; +inline static std::string METHOD_ERROR = "method error"; +inline static std::string INVALID_FILE_PATH = "invalid file path"; +inline static std::string OPEN_FAILED = "open file failed"; +inline static std::string FILE_SIZE_ERROR = "filesize error"; +inline static std::string RESP_PARSE_ERROR = "http response parse error"; +inline static std::string INVALID_CHUNK_SIZE = "invalid chunk size"; +inline static std::string READ_TIMEOUT = "read timeout"; + +class http_client : public std::enable_shared_from_this { +public: + http_client(boost::asio::io_service &ios) + : ios_(ios), resolver_(ios), socket_(ios), timer_(ios) { + future_ = read_close_finished_.get_future(); + } + + ~http_client() { close(); } + + response_data get(std::string uri) { + return request(http_method::GET, std::move(uri), req_content_type::json, + timeout_seconds_); + } + + response_data get(std::string uri, size_t seconds) { + return request(http_method::GET, std::move(uri), req_content_type::json, + seconds); + } + + response_data get(std::string uri, req_content_type type) { + return request(http_method::GET, std::move(uri), type, timeout_seconds_); + } + + response_data get(std::string uri, size_t seconds, req_content_type type) { + return request(http_method::GET, std::move(uri), type, seconds); + } + + response_data get(std::string uri, req_content_type type, size_t seconds) { + return request(http_method::GET, std::move(uri), type, seconds); + } + + response_data post(std::string uri, std::string body) { + return request(http_method::POST, std::move(uri), req_content_type::json, + timeout_seconds_, std::move(body)); + } + + response_data post(std::string uri, std::string body, req_content_type type) { + return request(http_method::POST, std::move(uri), type, timeout_seconds_, + std::move(body)); + } + + response_data post(std::string uri, std::string body, size_t seconds) { + return request(http_method::POST, std::move(uri), req_content_type::json, + seconds, std::move(body)); + } + + response_data post(std::string uri, std::string body, req_content_type type, + size_t seconds) { + return request(http_method::POST, std::move(uri), type, seconds, + std::move(body)); + } + + response_data post(std::string uri, std::string body, size_t seconds, + req_content_type type) { + return request(http_method::POST, std::move(uri), type, seconds, + std::move(body)); + } + + response_data request(http_method method, std::string uri, + req_content_type type = req_content_type::json, + size_t seconds = 15, std::string body = "") { + promise_ = std::make_shared>(); + sync_ = true; + if (!chunked_result_.empty()) { + chunked_result_.clear(); + } + + async_request(method, std::move(uri), nullptr, type, seconds, + std::move(body)); + auto future = promise_->get_future(); + auto status = future.wait_for(std::chrono::seconds(seconds)); + in_progress_ = false; + if (status == std::future_status::timeout) { + promise_ = nullptr; + return {boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, REQUEST_TIMEOUT}; + } + auto result = future.get(); + promise_ = nullptr; + return result; + } + + template + auto async_get(std::string uri, _Callback &&cb) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), req_content_type::json, + timeout_seconds_); + } + + template + auto async_get(std::string uri, req_content_type type, _Callback &&cb) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), type, timeout_seconds_); + } + + template + auto async_get(std::string uri, _Callback &&cb, req_content_type type) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), type, timeout_seconds_); + } + + template + auto async_get(std::string uri, _Callback &&cb, size_t seconds) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), req_content_type::json, + seconds); + } + + template + auto async_get(std::string uri, _Callback &&cb, req_content_type type, + size_t seconds) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), type, seconds); + } + + template + auto async_get(std::string uri, _Callback &&cb, size_t seconds, + req_content_type type) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), type, seconds); + } + + template + auto async_get(std::string uri, size_t seconds, _Callback &&cb) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), req_content_type::json, + seconds); + } + + template + auto async_get(std::string uri, req_content_type type, size_t seconds, + _Callback &&cb) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), type, seconds); + } + + template + auto async_get(std::string uri, size_t seconds, req_content_type type, + _Callback &&cb) { + return async_request(http_method::GET, std::move(uri), + std::forward<_Callback>(cb), type, seconds); + } + + template + auto async_post(std::string uri, std::string body, _Callback &&cb) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), req_content_type::json, + timeout_seconds_, std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, _Callback &&cb, + req_content_type type) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), type, timeout_seconds_, + std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, _Callback &&cb, + size_t seconds) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), req_content_type::json, + seconds, std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, _Callback &&cb, + req_content_type type, size_t seconds) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), type, seconds, + std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, _Callback &&cb, + size_t seconds, req_content_type type) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), type, seconds, + std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, req_content_type type, + _Callback &&cb) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), type, timeout_seconds_, + std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, size_t seconds, + _Callback &&cb) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), req_content_type::json, + seconds, std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, req_content_type type, + size_t seconds, _Callback &&cb) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), type, seconds, + std::move(body)); + } + + template + auto async_post(std::string uri, std::string body, size_t seconds, + req_content_type type, _Callback &&cb) { + return async_request(http_method::POST, std::move(uri), + std::forward<_Callback>(cb), type, seconds, + std::move(body)); + } + + template + auto async_request(http_method method, std::string uri, _Callable_t &&cb, + req_content_type type = req_content_type::json, + size_t seconds = 15, std::string body = "") + -> MODERN_CALLBACK_RESULT(void(response_data)) { + MODERN_CALLBACK_TRAITS(cb, void(response_data)); + async_request_impl(method, std::move(uri), MODERN_CALLBACK_CALL(), type, + seconds, std::move(body)); + MODERN_CALLBACK_RETURN(); + } + void async_request_impl(http_method method, std::string uri, callback_t cb, + req_content_type type = req_content_type::json, + size_t seconds = 15, std::string body = "") { + bool need_switch = false; + if (!promise_) { // just for async request, guard continuous async request, + // it's not allowed; async request must be after last one + // finished! + need_switch = sync_; + sync_ = false; + } + + if (in_progress_) { + set_error_value(cb, boost::asio::error::basic_errors::in_progress, + MULTIPLE_REQUEST); + return; + } else { + in_progress_ = true; + } + + if (method != http_method::POST && !body.empty()) { + set_error_value(cb, boost::asio::error::basic_errors::invalid_argument, + METHOD_ERROR); + return; + } + + bool init = last_domain_.empty(); + bool need_reset = + need_switch || (!init && (uri.find(last_domain_) == std::string::npos)); + + if (need_reset) { + close(false); + + // wait for read close finish + future_.wait(); + read_close_finished_ = {}; + future_ = read_close_finished_.get_future(); + + reset_socket(); + } + + auto [r, u] = get_uri(uri); + if (!r) { + set_error_value(cb, boost::asio::error::basic_errors::invalid_argument, + INVALID_URI); + return; + } + + last_domain_ = std::string(u.schema).append("://").append(u.host); + timeout_seconds_ = seconds; + req_content_type_ = type; + cb_ = std::move(cb); + context ctx(u, method, std::move(body)); + if (promise_) { + weak_ = promise_; + } + if (has_connected_) { + do_write(std::move(ctx)); + } else { + async_connect(std::move(ctx)); + } + } + + template + auto download(std::string src_file, std::string dest_file, _Callable_t &&cb, + size_t seconds = 60) { + return download(std::move(src_file), std::move(dest_file), 0, std::move(cb), + seconds); + } + + template + auto download(std::string src_file, std::string dest_file, int64_t size, + _Callable_t &&cb, size_t seconds = 60) + -> MODERN_CALLBACK_RESULT(void(response_data)) { + MODERN_CALLBACK_TRAITS(cb, void(response_data)); + download_impl(std::move(src_file), std::move(dest_file), size, + MODERN_CALLBACK_CALL(), seconds); + MODERN_CALLBACK_RETURN(); + } + + void download_impl(std::string src_file, std::string dest_file, int64_t size, + callback_t cb, size_t seconds = 60) { + auto parant_path = fs::path(dest_file).parent_path(); + std::error_code code; + fs::create_directories(parant_path, code); + if (code) { + cb_ = std::move(cb); + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + INVALID_FILE_PATH); + return; + } + + if (size > 0) { + char buffer[20]; + auto p = i64toa_jeaiii(size, buffer); + add_header("cinatra_start_pos", std::string(buffer, p - buffer)); + } else { + int64_t file_size = fs::file_size(dest_file, code); + if (!code && file_size > 0) { + char buffer[20]; + auto p = i64toa_jeaiii(file_size, buffer); + add_header("cinatra_start_pos", std::string(buffer, p - buffer)); + } + } + + download_file_ = std::make_shared( + dest_file, std::ios::binary | std::ios::app); + if (!download_file_->is_open()) { + cb_ = std::move(cb); + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + OPEN_FAILED); + return; + } + + if (size > 0) { + char buffer[20]; + auto p = i64toa_jeaiii(size, buffer); + add_header("cinatra_start_pos", std::string(buffer, p - buffer)); + } else { + int64_t file_size = fs::file_size(dest_file, code); + if (!code && file_size > 0) { + char buffer[20]; + auto p = i64toa_jeaiii(file_size, buffer); + add_header("cinatra_start_pos", std::string(buffer, p - buffer)); + } + } + + async_get(std::move(src_file), std::move(cb), req_content_type::none, + seconds); + } + + void download( + std::string src_file, + std::function chunk, + size_t seconds = 60) { + on_chunk_ = std::move(chunk); + async_get(std::move(src_file), nullptr, req_content_type::none, seconds); + } + + template + auto upload(std::string uri, std::string filename, _Callable_t &&cb, + size_t seconds = 60) { + return upload(std::move(uri), std::move(filename), 0, + std::forward<_Callable_t>(cb), seconds); + } + + template + auto upload(std::string uri, std::string filename, size_t start, + _Callable_t &&cb, size_t seconds = 60) { + multipart_str_ = std::move(filename); + start_ = start; + return async_request(http_method::POST, uri, std::forward<_Callable_t>(cb), + req_content_type::multipart, seconds, ""); + } + + void add_header(std::string key, std::string val) { + if (key.empty()) + return; + + if (key == "Host") + return; + + headers_.emplace_back(std::move(key), std::move(val)); + } + + void add_header_str(std::string pair_str) { + if (pair_str.empty()) + return; + + if (pair_str.find("Host:") != std::string::npos) + return; + + header_str_.append(pair_str); + } + + void clear_headers() { + if (!headers_.empty()) { + headers_.clear(); + } + + if (!header_str_.empty()) { + header_str_.clear(); + } + } + + std::pair get_resp_headers() { + if (!copy_headers_.empty()) + parser_.set_headers(copy_headers_); + + return parser_.get_headers(); + } + + std::string_view get_header_value(std::string_view key) { + return parser_.get_header_value(key); + } #ifdef CINATRA_ENABLE_SSL - void set_ssl_context_callback(std::function ssl_context_callback) { - ssl_context_callback_ = std::move(ssl_context_callback); - } + void set_ssl_context_callback( + std::function ssl_context_callback) { + ssl_context_callback_ = std::move(ssl_context_callback); + } #endif - private: - void callback(const boost::system::error_code& ec) { - callback(ec, 404, ""); - } +private: + void callback(const boost::system::error_code &ec) { callback(ec, 404, ""); } - void callback(const boost::system::error_code& ec, std::string error_msg) { - callback(ec, 404, std::move(error_msg)); - } + void callback(const boost::system::error_code &ec, std::string error_msg) { + callback(ec, 404, std::move(error_msg)); + } - void callback(const boost::system::error_code& ec, int status) { - callback(ec, status, ""); - } + void callback(const boost::system::error_code &ec, int status) { + callback(ec, status, ""); + } - void callback(const boost::system::error_code& ec, int status, std::string_view result) { - if (auto sp = weak_.lock(); sp) { - sp->set_value({ ec, status, result, get_resp_headers() }); - weak_.reset(); - return; - } + void callback(const boost::system::error_code &ec, int status, + std::string_view result) { + if (auto sp = weak_.lock(); sp) { + sp->set_value({ec, status, result, get_resp_headers()}); + weak_.reset(); + return; + } - if (cb_) { - cb_({ ec, status, result, get_resp_headers() }); - cb_ = nullptr; - } + if (cb_) { + cb_({ec, status, result, get_resp_headers()}); + cb_ = nullptr; + } - if (on_chunk_) { - on_chunk_(ec, result); - } + if (on_chunk_) { + on_chunk_(ec, result); + } - in_progress_ = false; - } + in_progress_ = false; + } - std::pair get_uri(const std::string& uri) { - uri_t u; - if (!u.parse_from(uri.data())) { - if (u.schema.empty()) - return { false, {} }; + std::pair get_uri(const std::string &uri) { + uri_t u; + if (!u.parse_from(uri.data())) { + if (u.schema.empty()) + return {false, {}}; - auto new_uri = url_encode(uri); + auto new_uri = url_encode(uri); - if (!u.parse_from(new_uri.data())) { - return { false, {} }; - } - } + if (!u.parse_from(new_uri.data())) { + return {false, {}}; + } + } - if (u.schema == "https"sv) { + if (u.schema == "https"sv) { #ifdef CINATRA_ENABLE_SSL - upgrade_to_ssl(); + upgrade_to_ssl(); #else - //please open CINATRA_ENABLE_SSL before request https! - assert(false); + // please open CINATRA_ENABLE_SSL before request https! + assert(false); #endif - } - - return { true, u }; - } + } + + return {true, u}; + } + + void async_connect(context ctx) { + reset_timer(); + boost::asio::ip::tcp::resolver::query query(ctx.host, ctx.port); + resolver_.async_resolve( + query, [this, self = this->shared_from_this(), ctx = std::move(ctx)]( + boost::system::error_code ec, + const boost::asio::ip::tcp::resolver::iterator &it) { + if (ec) { + callback(ec); + return; + } - void async_connect(context ctx) { - reset_timer(); - boost::asio::ip::tcp::resolver::query query(ctx.host, ctx.port); - resolver_.async_resolve(query, [this, self = this->shared_from_this(), ctx = std::move(ctx)] - (boost::system::error_code ec, const boost::asio::ip::tcp::resolver::iterator& it) { - if (ec) { - callback(ec); + boost::asio::async_connect( + socket_, it, + [this, self = shared_from_this(), ctx = std::move(ctx)]( + boost::system::error_code ec, + const boost::asio::ip::tcp::resolver::iterator &) { + cancel_timer(); + if (!ec) { + has_connected_ = true; + if (is_ssl()) { + handshake(std::move(ctx)); return; - } - - boost::asio::async_connect(socket_, it, [this, self = shared_from_this(), ctx = std::move(ctx)] - (boost::system::error_code ec, const boost::asio::ip::tcp::resolver::iterator&) { - cancel_timer(); - if (!ec) { - has_connected_ = true; - if (is_ssl()) { - handshake(std::move(ctx)); - return; - } - - do_read_write(ctx); - } - else { - callback(ec); - close(); - } - }); - }); - } - - void do_read_write(const context& ctx) { - boost::system::error_code error_ignored; - socket_.set_option(boost::asio::ip::tcp::no_delay(true), error_ignored); - do_read(); - do_write(ctx); - } + } - void do_write(const context& ctx) { - if (req_content_type_ == req_content_type::multipart) { - send_multipart_msg(ctx); - } - else { - send_msg(ctx); - } - } - - void send_msg(const context& ctx) { - write_msg_ = build_write_msg(ctx); - async_write(write_msg_, [this, self = shared_from_this()](const boost::system::error_code& ec, const size_t length) { - if (ec) { + do_read_write(ctx); + } else { + callback(ec); + close(); + } + }); + }); + } + + void do_read_write(const context &ctx) { + boost::system::error_code error_ignored; + socket_.set_option(boost::asio::ip::tcp::no_delay(true), error_ignored); + do_read(); + do_write(ctx); + } + + void do_write(const context &ctx) { + if (req_content_type_ == req_content_type::multipart) { + send_multipart_msg(ctx); + } else { + send_msg(ctx); + } + } + + void send_msg(const context &ctx) { + write_msg_ = build_write_msg(ctx); + async_write(write_msg_, + [this, self = shared_from_this()]( + const boost::system::error_code &ec, const size_t length) { + if (ec) { callback(ec); close(); return; - } - }); - } - - void send_multipart_msg(const context& ctx) { - auto filename = std::move(multipart_str_); - auto file = std::make_shared(filename, std::ios::binary); - if (!file) { - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), INVALID_FILE_PATH); - return; - } - - std::error_code ec; - size_t size = fs::file_size(filename, ec); - if (ec || start_ == -1) { - file->close(); - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), FILE_SIZE_ERROR); - return; - } - - if (start_ > 0) { - file->seekg(start_); - } - - auto left_file_size = size - start_; - header_str_.append("Content-Type: multipart/form-data; boundary=").append(BOUNDARY); - auto multipart_str = multipart_file_start(fs::path(filename).filename().string()); - auto write_str = build_write_msg(ctx, total_multipart_size(left_file_size, multipart_str.size())); - write_str.append(multipart_str); - multipart_str_ = std::move(write_str); - send_file_data(std::move(file)); - } - - void handshake(context ctx) { + } + }); + } + + void send_multipart_msg(const context &ctx) { + auto filename = std::move(multipart_str_); + auto file = std::make_shared(filename, std::ios::binary); + if (!file) { + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + INVALID_FILE_PATH); + return; + } + + std::error_code ec; + size_t size = fs::file_size(filename, ec); + if (ec || start_ == -1) { + file->close(); + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + FILE_SIZE_ERROR); + return; + } + + if (start_ > 0) { + file->seekg(start_); + } + + auto left_file_size = size - start_; + header_str_.append("Content-Type: multipart/form-data; boundary=") + .append(BOUNDARY); + auto multipart_str = + multipart_file_start(fs::path(filename).filename().string()); + auto write_str = build_write_msg( + ctx, total_multipart_size(left_file_size, multipart_str.size())); + write_str.append(multipart_str); + multipart_str_ = std::move(write_str); + send_file_data(std::move(file)); + } + + void handshake(context ctx) { #ifdef CINATRA_ENABLE_SSL - auto self = this->shared_from_this(); - ssl_stream_->async_handshake(boost::asio::ssl::stream_base::client, - [this, self, ctx = std::move(ctx)](const boost::system::error_code& ec) { - if (!ec) { - do_read_write(ctx); - } - else { - callback(ec); - close(); - } - }); + auto self = this->shared_from_this(); + ssl_stream_->async_handshake(boost::asio::ssl::stream_base::client, + [this, self, ctx = std::move(ctx)]( + const boost::system::error_code &ec) { + if (!ec) { + do_read_write(ctx); + } else { + callback(ec); + close(); + } + }); #endif - } - - std::string build_write_msg(const context& ctx, size_t content_len = 0) { - std::string write_msg(method_name(ctx.method)); - //can be optimized here - write_msg.append(" ").append(ctx.path); - if (!ctx.query.empty()) { - write_msg.append("?").append(ctx.query); - } - write_msg.append(" HTTP/1.1\r\nHost:"). - append(ctx.host).append("\r\n"); - - if (header_str_.find("Content-Type") == std::string::npos) { - auto type_str = get_content_type_str(req_content_type_); - if (!type_str.empty()) { - headers_.emplace_back("Content-Type", std::move(type_str)); - } - } - - bool has_connection = false; - //add user header - if (!headers_.empty()) { - for (auto& pair : headers_) { - if (pair.first == "Connection") { - has_connection = true; - } - write_msg.append(pair.first).append(": ").append(pair.second).append("\r\n"); - } - } - - if (!header_str_.empty()) { - if (header_str_.find("Connection")!=std::string::npos) { - has_connection = true; - } - write_msg.append(header_str_).append("\r\n"); - } - - //add content - if (!ctx.body.empty()) { - char buffer[20]; - auto p = i32toa_jeaiii((int)ctx.body.size(), buffer); - - write_msg.append("Content-Length: ").append(buffer, p - buffer).append("\r\n"); - } - else { - if (ctx.method == http_method::POST) { - if (content_len > 0) { - char buffer[20]; - auto p = i32toa_jeaiii((int)content_len, buffer); - - write_msg.append("Content-Length: ").append(buffer, p - buffer).append("\r\n"); - } - else { - write_msg.append("Content-Length: 0\r\n"); - } - } - } - - if (!has_connection) { - write_msg.append("Connection: keep-alive\r\n"); - } - - write_msg.append("\r\n"); - - if (!ctx.body.empty()) { - write_msg.append(std::move(ctx.body)); - } - - return write_msg; - } - - void do_read() { - reset_timer(); - async_read_until(TWO_CRCF, [this, self = shared_from_this()](auto ec, size_t size) { - cancel_timer(); - if (!ec) { - //parse header - const char* data_ptr = boost::asio::buffer_cast(read_buf_.data()); - size_t buf_size = read_buf_.size(); - int ret = parser_.parse_response(data_ptr, size, 0); - read_buf_.consume(size); - if (ret < 0) { - callback(boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), 404, - RESP_PARSE_ERROR); - if (buf_size > size) { - read_buf_.consume(buf_size - size); - } - - read_or_close(parser_.keep_alive()); - return; - } - - bool is_chunked = parser_.is_chunked(); - - if (is_chunked) { - copy_headers(); - //read_chunk_header - read_chunk_head(parser_.keep_alive()); - } - else { - if (parser_.body_len() == 0) { - callback(ec, parser_.status()); - - read_or_close(parser_.keep_alive()); - return; - } - - size_t content_len = (size_t)parser_.body_len(); - if ((size_t)parser_.total_len() <= buf_size) { - callback(ec, parser_.status(), { data_ptr + parser_.header_len(), content_len }); - read_buf_.consume(content_len); - - read_or_close(parser_.keep_alive()); - return; - } - - size_t size_to_read = content_len - read_buf_.size(); - copy_headers(); - do_read_body(parser_.keep_alive(), parser_.status(), size_to_read); - } - } - else { - callback(ec); - close(); - - //read close finish - if(!is_ready()) - read_close_finished_.set_value(true); - } - }); - } + } + + std::string build_write_msg(const context &ctx, size_t content_len = 0) { + std::string write_msg(method_name(ctx.method)); + // can be optimized here + write_msg.append(" ").append(ctx.path); + if (!ctx.query.empty()) { + write_msg.append("?").append(ctx.query); + } + write_msg.append(" HTTP/1.1\r\nHost:").append(ctx.host).append("\r\n"); + + if (header_str_.find("Content-Type") == std::string::npos) { + auto type_str = get_content_type_str(req_content_type_); + if (!type_str.empty()) { + headers_.emplace_back("Content-Type", std::move(type_str)); + } + } + + bool has_connection = false; + // add user header + if (!headers_.empty()) { + for (auto &pair : headers_) { + if (pair.first == "Connection") { + has_connection = true; + } + write_msg.append(pair.first) + .append(": ") + .append(pair.second) + .append("\r\n"); + } + } + + if (!header_str_.empty()) { + if (header_str_.find("Connection") != std::string::npos) { + has_connection = true; + } + write_msg.append(header_str_).append("\r\n"); + } + + // add content + if (!ctx.body.empty()) { + char buffer[20]; + auto p = i32toa_jeaiii((int)ctx.body.size(), buffer); + + write_msg.append("Content-Length: ") + .append(buffer, p - buffer) + .append("\r\n"); + } else { + if (ctx.method == http_method::POST) { + if (content_len > 0) { + char buffer[20]; + auto p = i32toa_jeaiii((int)content_len, buffer); + + write_msg.append("Content-Length: ") + .append(buffer, p - buffer) + .append("\r\n"); + } else { + write_msg.append("Content-Length: 0\r\n"); + } + } + } + + if (!has_connection) { + write_msg.append("Connection: keep-alive\r\n"); + } + + write_msg.append("\r\n"); + + if (!ctx.body.empty()) { + write_msg.append(std::move(ctx.body)); + } + + return write_msg; + } + + void do_read() { + reset_timer(); + async_read_until(TWO_CRCF, [this, self = shared_from_this()](auto ec, + size_t size) { + cancel_timer(); + if (!ec) { + // parse header + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + size_t buf_size = read_buf_.size(); + int ret = parser_.parse_response(data_ptr, size, 0); + read_buf_.consume(size); + if (ret < 0) { + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, RESP_PARSE_ERROR); + if (buf_size > size) { + read_buf_.consume(buf_size - size); + } - bool is_ready() { - return future_.wait_for(std::chrono::seconds(0)) == std::future_status::ready; + read_or_close(parser_.keep_alive()); + return; } - void do_read_body(bool keep_alive, int status, size_t size_to_read) { - reset_timer(); - async_read(size_to_read, [this, self = shared_from_this(), keep_alive, status](auto ec, size_t size) { - cancel_timer(); - if (!ec) { - size_t data_size = read_buf_.size(); - const char* data_ptr = boost::asio::buffer_cast(read_buf_.data()); + bool is_chunked = parser_.is_chunked(); - callback(ec, status, { data_ptr, data_size }); - - read_buf_.consume(data_size); - - read_or_close(keep_alive); - } - else { - callback(ec); - close(); - } - }); - } + if (is_chunked) { + copy_headers(); + // read_chunk_header + read_chunk_head(parser_.keep_alive()); + } else { + if (parser_.body_len() == 0) { + callback(ec, parser_.status()); - void read_or_close(bool keep_alive) { - if (keep_alive) { - do_read(); - } - else { - close(); - } - } - - void read_chunk_head(bool keep_alive) { - async_read_until(CRCF, [this, self = shared_from_this(), - keep_alive](auto ec, size_t size) { - if (!ec) { - size_t buf_size = read_buf_.size(); - /// simplify - size_t additional_size = buf_size - size; - const char* data_ptr = - boost::asio::buffer_cast(read_buf_.data()); - std::string_view size_str(data_ptr, size - CRCF.size()); - auto chunk_size = hex_to_int(size_str); - read_buf_.consume(size); - if (chunk_size < 0) { - callback( - boost::asio::error::make_error_code( - boost::asio::error::basic_errors::invalid_argument), - 404, INVALID_CHUNK_SIZE); - read_or_close(keep_alive); - return; - } - - if (additional_size < (chunk_size + 2)) { - //Not a complete chunk. - read_chunk_body(keep_alive, chunk_size, chunk_size + 2 - additional_size); - } - else { - //A complete chunk. - read_chunk(keep_alive, chunk_size); - } - } - else { - callback(ec); - close(); - } - }); - } - - void read_chunk(bool keep_alive, size_t length) { - if (length > 0) { - const char* data = - boost::asio::buffer_cast(read_buf_.data()); - append_chunk(std::string_view(data, length)); - read_buf_.consume(length + CRCF.size()); - read_chunk_head(keep_alive); - } - else { - callback({}, 200, chunked_result_); - clear_chunk_buffer(); - do_read(); + read_or_close(parser_.keep_alive()); + return; } - } - void read_chunk_body(bool keep_alive, size_t chunk_size, size_t size_to_read) { - async_read(size_to_read, [this, self = shared_from_this(), keep_alive, chunk_size](auto ec, size_t size) { - if (!ec) { - read_chunk(keep_alive, chunk_size); - } - else { - callback(ec); - close(); - } - }); - } + size_t content_len = (size_t)parser_.body_len(); + if ((size_t)parser_.total_len() <= buf_size) { + callback(ec, parser_.status(), + {data_ptr + parser_.header_len(), content_len}); + read_buf_.consume(content_len); - void append_chunk(std::string_view chunk) { - if (on_chunk_) { - on_chunk_({}, chunk); + read_or_close(parser_.keep_alive()); return; } - if (download_file_) { - download_file_->write(chunk.data(), chunk.size()); - } - else { - chunked_result_.append(chunk); - } - } - - void clear_chunk_buffer() { - if (download_file_) { - download_file_->close(); - } - else { - if (!sync_&&!chunked_result_.empty()) { - chunked_result_.clear(); - } - } - } - - template - void async_read(size_t size_to_read, Handler handler) { - if (is_ssl()) { + size_t size_to_read = content_len - read_buf_.size(); + copy_headers(); + do_read_body(parser_.keep_alive(), parser_.status(), size_to_read); + } + } else { + callback(ec); + close(); + + // read close finish + if (!is_ready()) + read_close_finished_.set_value(true); + } + }); + } + + bool is_ready() { + return future_.wait_for(std::chrono::seconds(0)) == + std::future_status::ready; + } + + void do_read_body(bool keep_alive, int status, size_t size_to_read) { + reset_timer(); + async_read(size_to_read, [this, self = shared_from_this(), keep_alive, + status](auto ec, size_t size) { + cancel_timer(); + if (!ec) { + size_t data_size = read_buf_.size(); + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + + callback(ec, status, {data_ptr, data_size}); + + read_buf_.consume(data_size); + + read_or_close(keep_alive); + } else { + callback(ec); + close(); + } + }); + } + + void read_or_close(bool keep_alive) { + if (keep_alive) { + do_read(); + } else { + close(); + } + } + + void read_chunk_head(bool keep_alive) { + async_read_until(CRCF, [this, self = shared_from_this(), + keep_alive](auto ec, size_t size) { + if (!ec) { + size_t buf_size = read_buf_.size(); + /// simplify + size_t additional_size = buf_size - size; + const char *data_ptr = + boost::asio::buffer_cast(read_buf_.data()); + std::string_view size_str(data_ptr, size - CRCF.size()); + auto chunk_size = hex_to_int(size_str); + read_buf_.consume(size); + if (chunk_size < 0) { + callback(boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, INVALID_CHUNK_SIZE); + read_or_close(keep_alive); + return; + } + + if (additional_size < (chunk_size + 2)) { + // Not a complete chunk. + read_chunk_body(keep_alive, chunk_size, + chunk_size + 2 - additional_size); + } else { + // A complete chunk. + read_chunk(keep_alive, chunk_size); + } + } else { + callback(ec); + close(); + } + }); + } + + void read_chunk(bool keep_alive, size_t length) { + if (length > 0) { + const char *data = + boost::asio::buffer_cast(read_buf_.data()); + append_chunk(std::string_view(data, length)); + read_buf_.consume(length + CRCF.size()); + read_chunk_head(keep_alive); + } else { + callback({}, 200, chunked_result_); + clear_chunk_buffer(); + do_read(); + } + } + + void read_chunk_body(bool keep_alive, size_t chunk_size, + size_t size_to_read) { + async_read(size_to_read, [this, self = shared_from_this(), keep_alive, + chunk_size](auto ec, size_t size) { + if (!ec) { + read_chunk(keep_alive, chunk_size); + } else { + callback(ec); + close(); + } + }); + } + + void append_chunk(std::string_view chunk) { + if (on_chunk_) { + on_chunk_({}, chunk); + return; + } + + if (download_file_) { + download_file_->write(chunk.data(), chunk.size()); + } else { + chunked_result_.append(chunk); + } + } + + void clear_chunk_buffer() { + if (download_file_) { + download_file_->close(); + } else { + if (!sync_ && !chunked_result_.empty()) { + chunked_result_.clear(); + } + } + } + + template + void async_read(size_t size_to_read, Handler handler) { + if (is_ssl()) { #ifdef CINATRA_ENABLE_SSL - boost::asio::async_read(*ssl_stream_, read_buf_, boost::asio::transfer_exactly(size_to_read), std::move(handler)); + boost::asio::async_read(*ssl_stream_, read_buf_, + boost::asio::transfer_exactly(size_to_read), + std::move(handler)); #endif - } - else { - boost::asio::async_read(socket_, read_buf_, boost::asio::transfer_exactly(size_to_read), std::move(handler)); - } - } - - template - void async_read_until(const std::string& delim, Handler handler) { - if (is_ssl()) { + } else { + boost::asio::async_read(socket_, read_buf_, + boost::asio::transfer_exactly(size_to_read), + std::move(handler)); + } + } + + template + void async_read_until(const std::string &delim, Handler handler) { + if (is_ssl()) { #ifdef CINATRA_ENABLE_SSL - boost::asio::async_read_until(*ssl_stream_, read_buf_, delim, std::move(handler)); + boost::asio::async_read_until(*ssl_stream_, read_buf_, delim, + std::move(handler)); #endif - } - else { - boost::asio::async_read_until(socket_, read_buf_, delim, std::move(handler)); - } - } - - template - void async_write(const std::string& msg, Handler handler) { - if (is_ssl()) { + } else { + boost::asio::async_read_until(socket_, read_buf_, delim, + std::move(handler)); + } + } + + template + void async_write(const std::string &msg, Handler handler) { + if (is_ssl()) { #ifdef CINATRA_ENABLE_SSL - boost::asio::async_write(*ssl_stream_, boost::asio::buffer(msg), std::move(handler)); + boost::asio::async_write(*ssl_stream_, boost::asio::buffer(msg), + std::move(handler)); #endif - } - else { - boost::asio::async_write(socket_, boost::asio::buffer(msg), std::move(handler)); - } - } - - void close(bool close_ssl = true) { - boost::system::error_code ec; - if (close_ssl) { + } else { + boost::asio::async_write(socket_, boost::asio::buffer(msg), + std::move(handler)); + } + } + + void close(bool close_ssl = true) { + boost::system::error_code ec; + if (close_ssl) { #ifdef CINATRA_ENABLE_SSL - if (ssl_stream_) { - ssl_stream_->shutdown(ec); - ssl_stream_ = nullptr; - } + if (ssl_stream_) { + ssl_stream_->shutdown(ec); + ssl_stream_ = nullptr; + } #endif - } - - if (!has_connected_) - return; - - has_connected_ = false; - timer_.cancel(ec); - socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - socket_.close(ec); - } - - void reset_timer() { - if (timeout_seconds_ == 0 || promise_) { - return; - } - - auto self(this->shared_from_this()); - timer_.expires_from_now(std::chrono::seconds(timeout_seconds_)); - timer_.async_wait([this, self](const boost::system::error_code& ec) { - if (ec || sync_) { - return; - } - - close(false); //don't close ssl now, close ssl when read/write error - if (download_file_) { - download_file_->close(); - } - }); - } - - void cancel_timer() { - if (!cb_) { - return; //just for async request - } - - if (timeout_seconds_ == 0 || promise_) { - return; - } - - timer_.cancel(); - } - - bool is_ssl() const { + } + + if (!has_connected_) + return; + + has_connected_ = false; + timer_.cancel(ec); + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + socket_.close(ec); + } + + void reset_timer() { + if (timeout_seconds_ == 0 || promise_) { + return; + } + + auto self(this->shared_from_this()); + timer_.expires_from_now(std::chrono::seconds(timeout_seconds_)); + timer_.async_wait([this, self](const boost::system::error_code &ec) { + if (ec || sync_) { + return; + } + + close(false); // don't close ssl now, close ssl when read/write error + if (download_file_) { + download_file_->close(); + } + }); + } + + void cancel_timer() { + if (!cb_) { + return; // just for async request + } + + if (timeout_seconds_ == 0 || promise_) { + return; + } + + timer_.cancel(); + } + + bool is_ssl() const { #ifdef CINATRA_ENABLE_SSL - return ssl_stream_ != nullptr; + return ssl_stream_ != nullptr; #else - return false; + return false; #endif - } + } #ifdef CINATRA_ENABLE_SSL - void upgrade_to_ssl() { - if (ssl_stream_) - return; - - boost::asio::ssl::context ssl_context(boost::asio::ssl::context::sslv23); - ssl_context.set_default_verify_paths(); - boost::system::error_code ec; - ssl_context.set_options(boost::asio::ssl::context::default_workarounds, ec); - if (ssl_context_callback_) { - ssl_context_callback_(ssl_context); - } - ssl_stream_ = std::make_unique>(socket_, ssl_context); - //verify peer TODO - } + void upgrade_to_ssl() { + if (ssl_stream_) + return; + + boost::asio::ssl::context ssl_context(boost::asio::ssl::context::sslv23); + ssl_context.set_default_verify_paths(); + boost::system::error_code ec; + ssl_context.set_options(boost::asio::ssl::context::default_workarounds, ec); + if (ssl_context_callback_) { + ssl_context_callback_(ssl_context); + } + ssl_stream_ = std::make_unique< + boost::asio::ssl::stream>(socket_, + ssl_context); + // verify peer TODO + } #endif - void send_file_data(std::shared_ptr file) { - auto eof = make_upload_data(*file); - if (eof) { - return; - } - - auto self = this->shared_from_this(); - async_write(multipart_str_, [this, self, file = std::move(file)](boost::system::error_code ec, std::size_t length) mutable { - if (!ec) { + void send_file_data(std::shared_ptr file) { + auto eof = make_upload_data(*file); + if (eof) { + return; + } + + auto self = this->shared_from_this(); + async_write(multipart_str_, + [this, self, file = std::move(file)]( + boost::system::error_code ec, std::size_t length) mutable { + if (!ec) { multipart_str_.clear(); send_file_data(std::move(file)); - } - else { + } else { on_chunk_(ec, "send failed"); close(); - } - }); - } - - std::string multipart_file_start(std::string filename) { - std::string multipart_start; - multipart_start.append("--" + BOUNDARY + CRCF); - multipart_start.append("Content-Disposition: form-data; name=\"" + std::string("test") + "\"; filename=\"" + std::move(filename) + "\"" + CRCF); - multipart_start.append(CRCF); - return multipart_start; - } - - size_t total_multipart_size(size_t left_file_size, size_t multipart_start_size) { - return left_file_size + multipart_start_size + MULTIPART_END.size(); - } - - bool make_upload_data(std::ifstream& file) { - bool eof = file.peek() == EOF; - if (eof) { - file.close(); - return true;//finish all file - } - - std::string content; - const size_t size = 3 * 1024 * 1024; - content.resize(size); - file.read(&content[0], size); - int64_t read_len = (int64_t)file.gcount(); - assert(read_len > 0); - eof = file.peek() == EOF; - - if (read_len < size) { - content.resize(read_len); - } - - multipart_str_.append(content); - if (eof) { - multipart_str_.append(MULTIPART_END); - } - - return false; - } - - void copy_headers() { - if (!copy_headers_.empty()) { - copy_headers_.clear(); - } - auto [headers, num_headers] = parser_.get_headers(); - for (size_t i = 0; i < num_headers; i++) { - copy_headers_.emplace_back(std::string(headers[i].name, headers[i].name_len), - std::string(headers[i].value, headers[i].value_len)); - } - } - - void reset_socket() { - boost::system::error_code igored_ec; - socket_ = decltype(socket_)(ios_); - if (!socket_.is_open()) { - socket_.open(boost::asio::ip::tcp::v4(), igored_ec); - } - } - - void set_error_value(const callback_t& cb, const boost::asio::error::basic_errors& ec, const std::string& error_msg) { - if (promise_) { - promise_->set_value({ boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), 404, error_msg }); - } - if (cb) { - cb({ boost::asio::error::make_error_code(boost::asio::error::basic_errors::invalid_argument), 404, error_msg }); - } - read_close_finished_ = {}; - } - - private: - std::atomic_bool has_connected_ = false; - callback_t cb_; - std::atomic_bool in_progress_ = false; - - boost::asio::io_service& ios_; - boost::asio::ip::tcp::resolver resolver_; - boost::asio::ip::tcp::socket socket_; + } + }); + } + + std::string multipart_file_start(std::string filename) { + std::string multipart_start; + multipart_start.append("--" + BOUNDARY + CRCF); + multipart_start.append("Content-Disposition: form-data; name=\"" + + std::string("test") + "\"; filename=\"" + + std::move(filename) + "\"" + CRCF); + multipart_start.append(CRCF); + return multipart_start; + } + + size_t total_multipart_size(size_t left_file_size, + size_t multipart_start_size) { + return left_file_size + multipart_start_size + MULTIPART_END.size(); + } + + bool make_upload_data(std::ifstream &file) { + bool eof = file.peek() == EOF; + if (eof) { + file.close(); + return true; // finish all file + } + + std::string content; + const size_t size = 3 * 1024 * 1024; + content.resize(size); + file.read(&content[0], size); + int64_t read_len = (int64_t)file.gcount(); + assert(read_len > 0); + eof = file.peek() == EOF; + + if (read_len < size) { + content.resize(read_len); + } + + multipart_str_.append(content); + if (eof) { + multipart_str_.append(MULTIPART_END); + } + + return false; + } + + void copy_headers() { + if (!copy_headers_.empty()) { + copy_headers_.clear(); + } + auto [headers, num_headers] = parser_.get_headers(); + for (size_t i = 0; i < num_headers; i++) { + copy_headers_.emplace_back( + std::string(headers[i].name, headers[i].name_len), + std::string(headers[i].value, headers[i].value_len)); + } + } + + void reset_socket() { + boost::system::error_code igored_ec; + socket_ = decltype(socket_)(ios_); + if (!socket_.is_open()) { + socket_.open(boost::asio::ip::tcp::v4(), igored_ec); + } + } + + void set_error_value(const callback_t &cb, + const boost::asio::error::basic_errors &ec, + const std::string &error_msg) { + if (promise_) { + promise_->set_value( + {boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, error_msg}); + } + if (cb) { + cb({boost::asio::error::make_error_code( + boost::asio::error::basic_errors::invalid_argument), + 404, error_msg}); + } + read_close_finished_ = {}; + } + +private: + std::atomic_bool has_connected_ = false; + callback_t cb_; + std::atomic_bool in_progress_ = false; + + boost::asio::io_service &ios_; + boost::asio::ip::tcp::resolver resolver_; + boost::asio::ip::tcp::socket socket_; #ifdef CINATRA_ENABLE_SSL - std::unique_ptr> ssl_stream_; - std::function ssl_context_callback_; + std::unique_ptr> + ssl_stream_; + std::function ssl_context_callback_; #endif - boost::asio::steady_timer timer_; - std::size_t timeout_seconds_ = 60; - boost::asio::streambuf read_buf_; - - http_parser parser_; - std::vector> copy_headers_; - std::string header_str_; - std::vector> headers_; - req_content_type req_content_type_ = req_content_type::json; - - std::string write_msg_; - - std::string chunked_result_; - std::shared_ptr download_file_ = nullptr; - std::function on_chunk_ = nullptr; - - std::string multipart_str_; - size_t start_; - - std::string last_domain_; - std::promise read_close_finished_; - std::future future_; - - std::shared_ptr> promise_ = nullptr; - std::weak_ptr> weak_; - bool sync_ = false; - }; -} + boost::asio::steady_timer timer_; + std::size_t timeout_seconds_ = 60; + boost::asio::streambuf read_buf_; + + http_parser parser_; + std::vector> copy_headers_; + std::string header_str_; + std::vector> headers_; + req_content_type req_content_type_ = req_content_type::json; + + std::string write_msg_; + + std::string chunked_result_; + std::shared_ptr download_file_ = nullptr; + std::function on_chunk_ = + nullptr; + + std::string multipart_str_; + size_t start_; + + std::string last_domain_; + std::promise read_close_finished_; + std::future future_; + + std::shared_ptr> promise_ = nullptr; + std::weak_ptr> weak_; + bool sync_ = false; +}; +} // namespace cinatra diff --git a/include/cinatra/http_parser.hpp b/include/cinatra/http_parser.hpp index 2325003..4519453 100644 --- a/include/cinatra/http_parser.hpp +++ b/include/cinatra/http_parser.hpp @@ -1,120 +1,113 @@ #pragma once -#include -#include #include "picohttpparser.h" +#include +#include using namespace std::string_view_literals; namespace cinatra { - class http_parser { - public: - int parse_response(const char* data, size_t size, int last_len) { - int minor_version; - - num_headers_ = sizeof(headers_) / sizeof(headers_[0]); - const char* msg; - size_t msg_len; - header_len_ = phr_parse_response(data, size, &minor_version, &status_, &msg, &msg_len, headers_, &num_headers_, last_len); - msg_ = { msg, msg_len }; - auto header_value = this->get_header_value("content-length"); - if (header_value.empty()) { - body_len_ = 0; - } - else { - body_len_ = atoi(header_value.data()); - } - - return header_len_; - } - - std::string_view get_header_value(std::string_view key) { - for (size_t i = 0; i < num_headers_; i++) { - if (iequal(headers_[i].name, headers_[i].name_len, key.data())) - return std::string_view(headers_[i].value, headers_[i].value_len); - } - - return {}; - } - - bool is_chunked() { - auto transfer_encoding = this->get_header_value("transfer-encoding"); - if (transfer_encoding == "chunked"sv) { - return true; - } - - return false; - } - - bool keep_alive() { - auto val = this->get_header_value("connection"); - if (val.empty()|| iequal(val.data(), val.length(), "keep-alive")) { - return true; - } - - return false; - } - - int status() const { - return status_; - } - - int header_len() const { - return header_len_; - } - - int body_len() const { - return body_len_; - } - - int total_len() const { - return header_len_ + body_len_; - } - - std::string_view msg() const { - return msg_; - } - - std::pair get_headers() { - return { headers_ , num_headers_ }; - } - - void set_headers(const std::vector>& headers) { - num_headers_ = headers.size(); - for (size_t i = 0; i < num_headers_; i++) { - headers_[i].name = headers[i].first.data(); - headers_[i].name_len = headers[i].first.size(); - headers_[i].value = headers[i].second.data(); - headers_[i].value_len = headers[i].second.size(); - } - } - - private: - std::string_view get_header_value(phr_header* headers, size_t num_headers, std::string_view key) { - for (size_t i = 0; i < num_headers; i++) { - if (iequal(headers[i].name, headers[i].name_len, key.data())) - return std::string_view(headers[i].value, headers[i].value_len); - } - - return {}; - } - - bool iequal(const char* s, size_t l, const char* t) { - if (strlen(t) != l) - return false; - - for (size_t i = 0; i < l; i++) { - if (std::tolower(s[i]) != std::tolower(t[i])) - return false; - } - - return true; - } - - int status_ = 0; - std::string_view msg_; - size_t num_headers_ = 0; - int header_len_ = 0; - int body_len_ = 0; - struct phr_header headers_[100]; - }; -} \ No newline at end of file +class http_parser { +public: + int parse_response(const char *data, size_t size, int last_len) { + int minor_version; + + num_headers_ = sizeof(headers_) / sizeof(headers_[0]); + const char *msg; + size_t msg_len; + header_len_ = + phr_parse_response(data, size, &minor_version, &status_, &msg, &msg_len, + headers_, &num_headers_, last_len); + msg_ = {msg, msg_len}; + auto header_value = this->get_header_value("content-length"); + if (header_value.empty()) { + body_len_ = 0; + } else { + body_len_ = atoi(header_value.data()); + } + + return header_len_; + } + + std::string_view get_header_value(std::string_view key) { + for (size_t i = 0; i < num_headers_; i++) { + if (iequal(headers_[i].name, headers_[i].name_len, key.data())) + return std::string_view(headers_[i].value, headers_[i].value_len); + } + + return {}; + } + + bool is_chunked() { + auto transfer_encoding = this->get_header_value("transfer-encoding"); + if (transfer_encoding == "chunked"sv) { + return true; + } + + return false; + } + + bool keep_alive() { + auto val = this->get_header_value("connection"); + if (val.empty() || iequal(val.data(), val.length(), "keep-alive")) { + return true; + } + + return false; + } + + int status() const { return status_; } + + int header_len() const { return header_len_; } + + int body_len() const { return body_len_; } + + int total_len() const { return header_len_ + body_len_; } + + std::string_view msg() const { return msg_; } + + std::pair get_headers() { + return {headers_, num_headers_}; + } + + void + set_headers(const std::vector> &headers) { + num_headers_ = headers.size(); + for (size_t i = 0; i < num_headers_; i++) { + headers_[i].name = headers[i].first.data(); + headers_[i].name_len = headers[i].first.size(); + headers_[i].value = headers[i].second.data(); + headers_[i].value_len = headers[i].second.size(); + } + } + +private: + std::string_view get_header_value(phr_header *headers, size_t num_headers, + std::string_view key) { + for (size_t i = 0; i < num_headers; i++) { + if (iequal(headers[i].name, headers[i].name_len, key.data())) + return std::string_view(headers[i].value, headers[i].value_len); + } + + return {}; + } + + bool iequal(const char *s, size_t l, const char *t) { + if (strlen(t) != l) + return false; + + for (size_t i = 0; i < l; i++) { + if (std::tolower(s[i]) != std::tolower(t[i])) + return false; + } + + return true; + } + + int status_ = 0; + std::string_view msg_; + size_t num_headers_ = 0; + int header_len_ = 0; + int body_len_ = 0; + struct phr_header headers_[100]; +}; +} // namespace cinatra \ No newline at end of file diff --git a/include/cinatra/http_router.hpp b/include/cinatra/http_router.hpp index 4385197..69d268e 100644 --- a/include/cinatra/http_router.hpp +++ b/include/cinatra/http_router.hpp @@ -1,216 +1,242 @@ #pragma once -#include -#include -#include -#include -#include -#include "request.hpp" -#include "response.hpp" -#include "utils.hpp" #include "function_traits.hpp" #include "mime_types.hpp" +#include "request.hpp" +#include "response.hpp" #include "session.hpp" +#include "utils.hpp" +#include +#include +#include +#include +#include namespace cinatra { - namespace{ - constexpr char DOT = '.'; - constexpr char SLASH = '/'; - constexpr std::string_view INDEX = "index"; +namespace { +constexpr char DOT = '.'; +constexpr char SLASH = '/'; +constexpr std::string_view INDEX = "index"; +} // namespace + +class http_router { +public: + template + std::enable_if_t> + register_handler(std::string_view name, Function &&f, const Ap &...ap) { + if constexpr (sizeof...(Is) > 0) { + auto arr = get_method_arr(); + register_nonmember_func(name, arr, std::forward(f), ap...); + } else { + register_nonmember_func(name, {0}, std::forward(f), ap...); } - - class http_router { - public: - template - std::enable_if_t> register_handler(std::string_view name, Function&& f, const Ap&... ap) { - if constexpr(sizeof...(Is) > 0) { - auto arr = get_method_arr(); - register_nonmember_func(name, arr, std::forward(f), ap...); - } - else { - register_nonmember_func(name, {0}, std::forward(f), ap...); - } - } - - template - std::enable_if_t> register_handler(std::string_view name, Type (T::* f)(request&, response&), T1 t, const Ap&... ap) { - register_handler_impl(name, f, t, ap...); - } - - template - void register_handler(std::string_view name, Type(T::* f)(request&, response&), const Ap&... ap) { - register_handler_impl(name, f, (T*)nullptr, ap...); - } - - void remove_handler(std::string name) { - this->map_invokers_.erase(name); - } - - //elimate exception, resut type bool: true, success, false, failed - bool route(std::string_view method, std::string_view url, request& req, response& res) { - auto it = map_invokers_.find(url); - if (it != map_invokers_.end()) { - auto& pair = it->second; - if (method[0] < 'A' || method[0] > 'Z') - return false; - - if (pair.first[method[0] - 65] == 0) { - return false; - } - - pair.second(req, res); - return true; - } - else { - if (url.rfind(DOT) != std::string_view::npos) { - url = STATIC_RESOURCE; - return route(method, url, req, res); - } - - return get_wildcard_function(url, req, res); - } - } - - private: - bool get_wildcard_function(std::string_view key, request& req, response& res) { - for (auto& pair : wildcard_invokers_) { - if (key.find(pair.first) != std::string::npos) { - auto& t = pair.second; - t.second(req, res); - return true; - } - } - return false; - } - - template - void register_handler_impl(std::string_view name, Type T::* f, T1 t, const Ap&... ap) { - if constexpr(sizeof...(Is) > 0) { - auto arr = get_method_arr(); - register_member_func(name, arr, f, t, ap...); - } - else { - register_member_func(name, {0}, f, t, ap...); - } - } - - template - void register_nonmember_func(std::string_view raw_name, const std::array& arr, Function f, const AP&... ap) { - if (raw_name.back()=='*') { - this->wildcard_invokers_[raw_name.substr(0, raw_name.length()-1)] = { arr, std::bind(&http_router::invoke, this, - std::placeholders::_1, std::placeholders::_2, std::move(f), ap...) }; - } - else { - this->map_invokers_[raw_name] = { arr, std::bind(&http_router::invoke, this, - std::placeholders::_1, std::placeholders::_2, std::move(f), ap...) }; - } - } - - template - void invoke(request& req, response& res, Function f, AP... ap) { - using result_type = std::result_of_t; - std::tuple tp(std::move(ap)...); - bool r = do_ap_before(req, res, tp); - - if (!r) - return; - - if constexpr(std::is_void_v) { - //business - f(req, res); - //after - do_void_after(req, res, tp); - } - else { - //business - result_type result = f(req, res); - //after - do_after(std::move(result), req, res, tp); - } - } - - template - void register_member_func(std::string_view raw_name, const std::array& arr, Function f, Self self, const AP&... ap) { - if (raw_name.back() == '*') { - this->wildcard_invokers_[raw_name.substr(0, raw_name.length() - 1)] = { arr, std::bind(&http_router::invoke_mem, this, - std::placeholders::_1, std::placeholders::_2, f, self, ap...) }; - } - else { - this->map_invokers_[raw_name] = { arr, std::bind(&http_router::invoke_mem, this, - std::placeholders::_1, std::placeholders::_2, f, self, ap...) }; - } - } - - template - void invoke_mem(request& req, response& res, Function f, Self self, AP... ap) { - using result_type = typename timax::function_traits::result_type; - std::tuple tp(std::move(ap)...); - bool r = do_ap_before(req, res, tp); - - if (!r) - return; - using nonpointer_type = std::remove_pointer_t; - if constexpr(std::is_void_v) { - //business - if(self) - (*self.*f)(req, res); - else - (nonpointer_type{}.*f)(req, res); - //after - do_void_after(req, res, tp); - } - else { - //business - result_type result; - if (self) - result = (*self.*f)(req, res); - else - result = (nonpointer_type{}.*f)(req, res); - //after - do_after(std::move(result), req, res, tp); - } - } - - template - bool do_ap_before(request& req, response& res, Tuple& tp) { - bool r = true; - for_each_l(tp, [&r, &req, &res](auto& item) { - if (!r) - return; - - constexpr bool has_befor_mtd = has_before::value; - if constexpr (has_befor_mtd) - r = item.before(req, res); - }, std::make_index_sequence>{}); - - return r; - } - - template - void do_void_after(request& req, response& res, Tuple& tp) { - bool r = true; - for_each_r(tp, [&r, &req, &res](auto& item) { - if (!r) - return; - - constexpr bool has_after_mtd = has_after::value; - if constexpr (has_after_mtd) - r = item.after(req, res); - }, std::make_index_sequence>{}); - } - - template - void do_after(T&& result, request& req, response& res, Tuple& tp) { - bool r = true; - for_each_r(tp, [&r, result = std::move(result), &req, &res](auto& item){ - if (!r) - return; - - if constexpr (has_after::value) - r = item.after(std::move(result), req, res); - }, std::make_index_sequence>{}); - } - - typedef std::pair, std::function> invoker_function; - std::map map_invokers_; - std::unordered_map wildcard_invokers_; //for url/* - }; -} + } + + template + std::enable_if_t> + register_handler(std::string_view name, Type (T::*f)(request &, response &), + T1 t, const Ap &...ap) { + register_handler_impl(name, f, t, ap...); + } + + template + void register_handler(std::string_view name, + Type (T::*f)(request &, response &), const Ap &...ap) { + register_handler_impl(name, f, (T *)nullptr, ap...); + } + + void remove_handler(std::string name) { this->map_invokers_.erase(name); } + + // elimate exception, resut type bool: true, success, false, failed + bool route(std::string_view method, std::string_view url, request &req, + response &res) { + auto it = map_invokers_.find(url); + if (it != map_invokers_.end()) { + auto &pair = it->second; + if (method[0] < 'A' || method[0] > 'Z') + return false; + + if (pair.first[method[0] - 65] == 0) { + return false; + } + + pair.second(req, res); + return true; + } else { + if (url.rfind(DOT) != std::string_view::npos) { + url = STATIC_RESOURCE; + return route(method, url, req, res); + } + + return get_wildcard_function(url, req, res); + } + } + +private: + bool get_wildcard_function(std::string_view key, request &req, + response &res) { + for (auto &pair : wildcard_invokers_) { + if (key.find(pair.first) != std::string::npos) { + auto &t = pair.second; + t.second(req, res); + return true; + } + } + return false; + } + + template + void register_handler_impl(std::string_view name, Type T::*f, T1 t, + const Ap &...ap) { + if constexpr (sizeof...(Is) > 0) { + auto arr = get_method_arr(); + register_member_func(name, arr, f, t, ap...); + } else { + register_member_func(name, {0}, f, t, ap...); + } + } + + template + void register_nonmember_func(std::string_view raw_name, + const std::array &arr, Function f, + const AP &...ap) { + if (raw_name.back() == '*') { + this->wildcard_invokers_[raw_name.substr(0, raw_name.length() - 1)] = { + arr, std::bind(&http_router::invoke, this, + std::placeholders::_1, std::placeholders::_2, + std::move(f), ap...)}; + } else { + this->map_invokers_[raw_name] = { + arr, std::bind(&http_router::invoke, this, + std::placeholders::_1, std::placeholders::_2, + std::move(f), ap...)}; + } + } + + template + void invoke(request &req, response &res, Function f, AP... ap) { + using result_type = std::result_of_t; + std::tuple tp(std::move(ap)...); + bool r = do_ap_before(req, res, tp); + + if (!r) + return; + + if constexpr (std::is_void_v) { + // business + f(req, res); + // after + do_void_after(req, res, tp); + } else { + // business + result_type result = f(req, res); + // after + do_after(std::move(result), req, res, tp); + } + } + + template + void register_member_func(std::string_view raw_name, + const std::array &arr, Function f, + Self self, const AP &...ap) { + if (raw_name.back() == '*') { + this->wildcard_invokers_[raw_name.substr(0, raw_name.length() - 1)] = { + arr, std::bind(&http_router::invoke_mem, this, + std::placeholders::_1, std::placeholders::_2, f, self, + ap...)}; + } else { + this->map_invokers_[raw_name] = { + arr, std::bind(&http_router::invoke_mem, this, + std::placeholders::_1, std::placeholders::_2, f, self, + ap...)}; + } + } + + template + void invoke_mem(request &req, response &res, Function f, Self self, + AP... ap) { + using result_type = typename timax::function_traits::result_type; + std::tuple tp(std::move(ap)...); + bool r = do_ap_before(req, res, tp); + + if (!r) + return; + using nonpointer_type = std::remove_pointer_t; + if constexpr (std::is_void_v) { + // business + if (self) + (*self.*f)(req, res); + else + (nonpointer_type{}.*f)(req, res); + // after + do_void_after(req, res, tp); + } else { + // business + result_type result; + if (self) + result = (*self.*f)(req, res); + else + result = (nonpointer_type{}.*f)(req, res); + // after + do_after(std::move(result), req, res, tp); + } + } + + template + bool do_ap_before(request &req, response &res, Tuple &tp) { + bool r = true; + for_each_l( + tp, + [&r, &req, &res](auto &item) { + if (!r) + return; + + constexpr bool has_befor_mtd = + has_before::value; + if constexpr (has_befor_mtd) + r = item.before(req, res); + }, + std::make_index_sequence>{}); + + return r; + } + + template + void do_void_after(request &req, response &res, Tuple &tp) { + bool r = true; + for_each_r( + tp, + [&r, &req, &res](auto &item) { + if (!r) + return; + + constexpr bool has_after_mtd = + has_after::value; + if constexpr (has_after_mtd) + r = item.after(req, res); + }, + std::make_index_sequence>{}); + } + + template + void do_after(T &&result, request &req, response &res, Tuple &tp) { + bool r = true; + for_each_r( + tp, + [&r, result = std::move(result), &req, &res](auto &item) { + if (!r) + return; + + if constexpr (has_after::value) + r = item.after(std::move(result), req, res); + }, + std::make_index_sequence>{}); + } + + typedef std::pair, + std::function> + invoker_function; + std::map map_invokers_; + std::unordered_map + wildcard_invokers_; // for url/* +}; +} // namespace cinatra diff --git a/include/cinatra/http_server.hpp b/include/cinatra/http_server.hpp index 4a163b6..fd2cfed 100644 --- a/include/cinatra/http_server.hpp +++ b/include/cinatra/http_server.hpp @@ -1,18 +1,18 @@ #pragma once #include "use_asio.hpp" #include -#include #include +#include -#include "io_service_pool.hpp" #include "connection.hpp" -#include "http_router.hpp" -#include "router.hpp" +#include "cookie.hpp" #include "function_traits.hpp" -#include "url_encode_decode.hpp" #include "http_cache.hpp" +#include "http_router.hpp" +#include "io_service_pool.hpp" +#include "router.hpp" #include "session_manager.hpp" -#include "cookie.hpp" +#include "url_encode_decode.hpp" namespace cinatra { @@ -27,7 +27,7 @@ class http_server_ : private noncopyable { public: using type = ScoketType; template - explicit http_server_(Args &&... args) + explicit http_server_(Args &&...args) : io_service_pool_(std::forward(args)...) { http_cache::get().set_cache_max_age(86400); init_conn_callback(); @@ -167,9 +167,10 @@ public: // set http handlers template - void set_http_handler(std::string_view name, Function &&f, AP &&... ap) { + void set_http_handler(std::string_view name, Function &&f, AP &&...ap) { if constexpr (has_type, - std::tuple...>>::value) { // for cache + std::tuple...>>::value) { // for + // cache bool b = false; ((!b && (b = need_cache(std::forward(ap)))), ...); if (!b) { @@ -429,7 +430,8 @@ private: void write_ranges_header(request &req, std::string_view mime, std::string filename, std::string file_size) { - std::string header_str = "HTTP/1.1 200 OK\r\nAccess-Control-Allow-origin: *\r\nAccept-Ranges: bytes\r\n"; + std::string header_str = "HTTP/1.1 200 OK\r\nAccess-Control-Allow-origin: " + "*\r\nAccept-Ranges: bytes\r\n"; header_str.append("Content-Disposition: attachment;filename="); header_str.append(std::move(filename)).append("\r\n"); header_str.append("Connection: keep-alive\r\n"); @@ -555,4 +557,4 @@ using http_server_proxy = http_server_; using http_server = http_server_proxy; using http_ssl_server = http_server_proxy; -} +} // namespace cinatra diff --git a/include/cinatra/io_service_pool.hpp b/include/cinatra/io_service_pool.hpp index 6b7af28..00dd2ca 100644 --- a/include/cinatra/io_service_pool.hpp +++ b/include/cinatra/io_service_pool.hpp @@ -1,115 +1,95 @@ #pragma once #include "use_asio.hpp" -#include +#include "utils.hpp" #include #include -#include "utils.hpp" +#include + +namespace cinatra { +class io_service_pool : private noncopyable { +public: + explicit io_service_pool(std::size_t pool_size) : next_io_service_(0) { + if (pool_size == 0) + pool_size = 1; // set default value as 1 + + for (std::size_t i = 0; i < pool_size; ++i) { + io_service_ptr io_service(new boost::asio::io_service); + work_ptr work(new boost::asio::io_service::work(*io_service)); + io_services_.push_back(io_service); + work_.push_back(work); + } + } + + void run() { + std::vector> threads; + for (std::size_t i = 0; i < io_services_.size(); ++i) { + threads.emplace_back(std::make_shared( + [](io_service_ptr svr) { svr->run(); }, io_services_[i])); + } + + for (std::size_t i = 0; i < threads.size(); ++i) + threads[i]->join(); + } + + intptr_t run_one() { return -1; } + + intptr_t poll() { return -1; } + + intptr_t poll_one() { return -1; } + + void stop() { + work_.clear(); + + for (std::size_t i = 0; i < io_services_.size(); ++i) + io_services_[i]->stop(); + } + + boost::asio::io_service &get_io_service() { + boost::asio::io_service &io_service = *io_services_[next_io_service_]; + ++next_io_service_; + if (next_io_service_ == io_services_.size()) + next_io_service_ = 0; + return io_service; + } + +private: + using io_service_ptr = std::shared_ptr; + using work_ptr = std::shared_ptr; + + std::vector io_services_; + std::vector work_; + std::size_t next_io_service_; +}; + +class io_service_inplace : private noncopyable { +public: + explicit io_service_inplace() { + io_services_ = std::make_shared(); + work_ = std::make_shared(*io_services_); + } + + void run() { io_services_->run(); } + + intptr_t run_one() { return io_services_->run_one(); } + + intptr_t poll() { return io_services_->poll(); } + + intptr_t poll_one() { return io_services_->poll_one(); } + + void stop() { + work_ = nullptr; + + if (io_services_) + io_services_->stop(); + } + + boost::asio::io_service &get_io_service() { return *io_services_; } + +private: + using io_service_ptr = std::shared_ptr; + using work_ptr = std::shared_ptr; -namespace cinatra -{ - class io_service_pool : private noncopyable{ - public: - explicit io_service_pool(std::size_t pool_size) : next_io_service_(0) { - if (pool_size == 0) - pool_size = 1; //set default value as 1 - - for (std::size_t i = 0; i < pool_size; ++i) - { - io_service_ptr io_service(new boost::asio::io_service); - work_ptr work(new boost::asio::io_service::work(*io_service)); - io_services_.push_back(io_service); - work_.push_back(work); - } - } - - void run() { - std::vector > threads; - for (std::size_t i = 0; i < io_services_.size(); ++i){ - threads.emplace_back(std::make_shared( - [](io_service_ptr svr) { - svr->run(); - }, io_services_[i])); - } - - for (std::size_t i = 0; i < threads.size(); ++i) - threads[i]->join(); - } - - intptr_t run_one() { - return -1; - } - - intptr_t poll() { - return -1; - } - - intptr_t poll_one() { - return -1; - } - - void stop() { - work_.clear(); - - for (std::size_t i = 0; i < io_services_.size(); ++i) - io_services_[i]->stop(); - } - - boost::asio::io_service& get_io_service() { - boost::asio::io_service& io_service = *io_services_[next_io_service_]; - ++next_io_service_; - if (next_io_service_ == io_services_.size()) - next_io_service_ = 0; - return io_service; - } - - private: - using io_service_ptr = std::shared_ptr; - using work_ptr = std::shared_ptr; - - std::vector io_services_; - std::vector work_; - std::size_t next_io_service_; - }; - - class io_service_inplace : private noncopyable{ - public: - explicit io_service_inplace() { - io_services_ = std::make_shared(); - work_ = std::make_shared(*io_services_); - } - - void run() { - io_services_->run(); - } - - intptr_t run_one() { - return io_services_->run_one(); - } - - intptr_t poll() { - return io_services_->poll(); - } - - intptr_t poll_one() { - return io_services_->poll_one(); - } - - void stop() { - work_ = nullptr; - - if (io_services_) - io_services_->stop(); - } - - boost::asio::io_service& get_io_service() { - return *io_services_; - } - - private: - using io_service_ptr = std::shared_ptr; - using work_ptr = std::shared_ptr; - - io_service_ptr io_services_; - work_ptr work_; - }; -} + io_service_ptr io_services_; + work_ptr work_; +}; +} // namespace cinatra diff --git a/include/cinatra/itoa.hpp b/include/cinatra/itoa.hpp index da5c396..69769d8 100644 --- a/include/cinatra/itoa.hpp +++ b/include/cinatra/itoa.hpp @@ -28,249 +28,238 @@ #include #include #include -#include // memcpy +#include // memcpy #include namespace dec_ { - // Using a lookup table to convert binary numbers from 0 to 99 - // into ascii characters as described by Andrei Alexandrescu in - // https://www.facebook.com/notes/facebook-engineering/ - // three-optimization-tips-for-c/10151361643253920/ - - template < typename T, size_t N, typename Gen, size_t... Is > - constexpr auto generate_array(Gen&& item, std::index_sequence) - { - return std::array{ {item(Is)...}}; - } - - const std::array - digits = generate_array([](size_t i) { - return char('0' + ((i % 2) ? ((i / 2) % 10) : ((i / 2) / 10))); - }, std::make_index_sequence<200>{}); - - // extern const std::array digits; - static inline uint16_t const& dd(uint8_t u) { - return reinterpret_cast(digits.data())[u]; - } +// Using a lookup table to convert binary numbers from 0 to 99 +// into ascii characters as described by Andrei Alexandrescu in +// https://www.facebook.com/notes/facebook-engineering/ +// three-optimization-tips-for-c/10151361643253920/ - template static constexpr T pow10(size_t x) { - return x ? 10*pow10(x-1) : 1; - } +template +constexpr auto generate_array(Gen &&item, std::index_sequence) { + return std::array{{item(Is)...}}; +} - // Division by a power of 10 is implemented using a multiplicative inverse. - // This strength reduction is also done by optimizing compilers, but - // presently the fastest results are produced by using the values - // for the multiplication and the shift as given by the algorithm - // described by Agner Fog in "Optimizing Subroutines in Assembly Language" - // - // http://www.agner.org/optimize/optimizing_assembly.pdf - // - // "Integer division by a constant (all processors) - // A floating point number can be divided by a constant by multiplying - // with the reciprocal. If we want to do the same with integers, we have - // to scale the reciprocal by 2n and then shift the product to the right - // by n. There are various algorithms for finding a suitable value of n - // and compensating for rounding errors. The algorithm described below - // was invented by Terje Mathisen, Norway, and not published elsewhere." - - // using uint128_t = unsigned __int128; - - template struct MulInv { - using type = UInt; - static constexpr bool a{ A }; - static constexpr UInt m{ M }; - static constexpr unsigned s{ S }; - }; - template struct UT; - template struct UT { using U = T; }; - template struct UT { - using U = typename UT::U; - }; - template using MI = typename UT, - MulInv< uint16_t, 1, 41943U, 22 >, - MulInv< uint32_t, 0, 3518437209U, 45 >, - MulInv< uint64_t, 0, 12379400392853802749U, 90 > - >::U; - template using U = typename MI::type; - - // struct QR holds the result of dividing an unsigned N-byte variable - // by 10^N resulting in - template struct QR { - U q; // quotient with fewer than 2*N decimal digits - U r; // remainder with at most N decimal digits - }; - template QR static inline split( U u ) { - constexpr MI mi{}; - U q = (mi.m * (U<2*N>(u)+mi.a)) >> mi.s; - return { q, U( u - q * pow10>(N) ) }; - } +const std::array digits = generate_array( + [](size_t i) { + return char('0' + ((i % 2) ? ((i / 2) % 10) : ((i / 2) / 10))); + }, + std::make_index_sequence<200>{}); - enum Direction {Fwd,Rev}; - - template < Direction D > - struct convert - { - //===----------------------------------------------------------===// - // output the digits in either a forward or reverse direction - // use memcpy so compiler handles alignment on target architecture. - // Typically generates one store to memory with an optimizing - // compiler for target architecture that supports unaligned access. - //===----------------------------------------------------------===// - - template - static inline char* out(char* p, T&& obj) { - if (D==Rev) p -= sizeof(T); - memcpy(p,reinterpret_cast(&obj),sizeof(T)); - if (D==Fwd) p += sizeof(T); - return p; - } - - //===----------------------------------------------------------===// - // head: find most significant digit, skip leading zeros - //===----------------------------------------------------------===// - - // "x" contains quotient and remainder after division by 10^N - // quotient is less than 10^N - template - static inline char* head(char* p, QR x) { - return ( D==Fwd - ?( tail( head(p,U(x.q)),x.r)) - :( head( tail(p,x.r),U(x.q)))); - } - - // "u" is less than 10^2*N - template - static inline char* head(char* p, UInt u) { - return ( u < pow10>(N) - ?( head(p,U(u))) - :( head(p,split(u)))); - } - - // recursion base case, selected when "u" is one byte - static inline char* head(char* p, U<1> u) { - return ( u < 10 - ?( out(p,'0'+u)) - :( out(p,dd(u)))); - } - - //===----------------------------------------------------------===// - // tail: produce all digits including leading zeros - //===----------------------------------------------------------===// - - // recursive step, "u" is less than 10^2*N - template - static inline char* tail(char* p, UInt u) { - QR x = split(u); - return ( D==Fwd - ?( tail( tail(p,U(x.q)),x.r)) - :( tail( tail(p,x.r),U(x.q)))); - } - - // recursion base case, selected when "u" is one byte - static inline char* tail(char* p, U<1> u) { return out(p,dd(u)); } - - //===----------------------------------------------------------===// - // large values are >= 10^2*N - // where x contains quotient and remainder after division by 10^N - //===----------------------------------------------------------===// - - template - static inline char* large(char* p, QR x) { - QR y = split(x.q); - return ( D==Fwd - ?( tail( tail( head(p,U(y.q)),y.r),x.r)) - :( head( tail( tail(p,x.r),y.r),U(y.q)))); - } - - //===----------------------------------------------------------===// - // handle values of "u" that might be >= 10^2*N - // where N is the size of "u" in bytes - //===----------------------------------------------------------===// - - template - static inline char* itoa(char* p, UInt u) { - if (u < pow10>(N)) return head(p,U(u)); - QR x = split(u); - return (u < pow10>(2*N) - ?( head(p,x)) - :( large(p,x))); - } - - // selected when "u" is one byte - static inline char* itoa(char* p, U<1> u) { - if (u < 10) return out(p,'0'+u); - if (u < 100) return out(p,dd(u)); - return ( D==Fwd - ?( out(out(p,'0'+u/100),dd(u%100))) - :( out(out(p,dd(u%100)),'0'+u/100))); - } - - //===----------------------------------------------------------===// - // handle unsigned and signed integral operands - //===----------------------------------------------------------===// - - // itoa: handle unsigned integral operands (selected by SFINAE) - template::value - && std::is_integral::value>* = nullptr> - static inline char* itoa( U u, char* p ) - { - return convert::template itoa(p,u); - } - - // itoa: handle signed integral operands (selected by SFINAE) - template::value - && std::is_integral::value>* = nullptr> - static inline char* itoa( I i, char* p ) - { - // Need "mask" to be filled with a copy of the sign bit. - // If "i" is a negative value, then the result of "operator >>" - // is implementation-defined, though usually it is an arithmetic - // right shift that replicates the sign bit. - // Use a conditional expression to be portable, - // a good optimizing compiler generates an arithmetic right shift - // and avoids the conditional branch. - U mask = i < 0 ? ~U(0) : 0; - // Now get the absolute value of "i" and cast to unsigned type U. - // Cannot use std::abs() because the result is undefined - // in 2's complement systems for the most-negative value. - // Want to avoid conditional branch for performance reasons since - // CPU branch prediction will be ineffective when negative values - // occur randomly. - // Let "u" be "i" cast to unsigned type U. - // Subtract "u" from 2*u if "i" is positive or 0 if "i" is negative. - // This yields the absolute value with the desired type without - // using a conditional branch and without invoking undefined or - // implementation defined behavior: - U u = ((2 * U(i)) & ~mask) - U(i); - // Unconditionally store a minus sign when producing digits - // in a forward direction and increment the pointer only if - // the value is in fact negative. - // This avoids a conditional branch and is safe because we will - // always produce at least one digit and it will overwrite the - // minus sign when the value is not negative. - if (D == Fwd) { *p = '-'; p += (mask&1); } - p = convert::template itoa(p,u); - if (D == Rev && mask) *--p = '-'; - return p; - } - }; +// extern const std::array digits; +static inline uint16_t const &dd(uint8_t u) { + return reinterpret_cast(digits.data())[u]; +} + +template static constexpr T pow10(size_t x) { + return x ? 10 * pow10(x - 1) : 1; +} + +// Division by a power of 10 is implemented using a multiplicative inverse. +// This strength reduction is also done by optimizing compilers, but +// presently the fastest results are produced by using the values +// for the multiplication and the shift as given by the algorithm +// described by Agner Fog in "Optimizing Subroutines in Assembly Language" +// +// http://www.agner.org/optimize/optimizing_assembly.pdf +// +// "Integer division by a constant (all processors) +// A floating point number can be divided by a constant by multiplying +// with the reciprocal. If we want to do the same with integers, we have +// to scale the reciprocal by 2n and then shift the product to the right +// by n. There are various algorithms for finding a suitable value of n +// and compensating for rounding errors. The algorithm described below +// was invented by Terje Mathisen, Norway, and not published elsewhere." + +// using uint128_t = unsigned __int128; + +template struct MulInv { + using type = UInt; + static constexpr bool a{A}; + static constexpr UInt m{M}; + static constexpr unsigned s{S}; +}; +template struct UT; +template struct UT { + using U = T; +}; +template struct UT { + using U = typename UT::U; +}; +template +using MI = typename UT, + MulInv, + MulInv, + MulInv>::U; +template using U = typename MI::type; + +// struct QR holds the result of dividing an unsigned N-byte variable +// by 10^N resulting in +template struct QR { + U q; // quotient with fewer than 2*N decimal digits + U r; // remainder with at most N decimal digits +}; +template QR static inline split(U u) { + constexpr MI mi{}; + U q = (mi.m * (U<2 * N>(u) + mi.a)) >> mi.s; + return {q, U(u - q * pow10>(N))}; } +enum Direction { Fwd, Rev }; + +template struct convert { + //===----------------------------------------------------------===// + // output the digits in either a forward or reverse direction + // use memcpy so compiler handles alignment on target architecture. + // Typically generates one store to memory with an optimizing + // compiler for target architecture that supports unaligned access. + //===----------------------------------------------------------===// + + template static inline char *out(char *p, T &&obj) { + if (D == Rev) + p -= sizeof(T); + memcpy(p, reinterpret_cast(&obj), sizeof(T)); + if (D == Fwd) + p += sizeof(T); + return p; + } + + //===----------------------------------------------------------===// + // head: find most significant digit, skip leading zeros + //===----------------------------------------------------------===// + + // "x" contains quotient and remainder after division by 10^N + // quotient is less than 10^N + template static inline char *head(char *p, QR x) { + return (D == Fwd ? (tail(head(p, U(x.q)), x.r)) + : (head(tail(p, x.r), U(x.q)))); + } + + // "u" is less than 10^2*N + template + static inline char *head(char *p, UInt u) { + return (u < pow10>(N) ? (head(p, U(u))) + : (head(p, split(u)))); + } + + // recursion base case, selected when "u" is one byte + static inline char *head(char *p, U<1> u) { + return (u < 10 ? (out(p, '0' + u)) : (out(p, dd(u)))); + } + + //===----------------------------------------------------------===// + // tail: produce all digits including leading zeros + //===----------------------------------------------------------===// + + // recursive step, "u" is less than 10^2*N + template + static inline char *tail(char *p, UInt u) { + QR x = split(u); + return (D == Fwd ? (tail(tail(p, U(x.q)), x.r)) + : (tail(tail(p, x.r), U(x.q)))); + } + + // recursion base case, selected when "u" is one byte + static inline char *tail(char *p, U<1> u) { return out(p, dd(u)); } + + //===----------------------------------------------------------===// + // large values are >= 10^2*N + // where x contains quotient and remainder after division by 10^N + //===----------------------------------------------------------===// + + template static inline char *large(char *p, QR x) { + QR y = split(x.q); + return (D == Fwd ? (tail(tail(head(p, U(y.q)), y.r), x.r)) + : (head(tail(tail(p, x.r), y.r), U(y.q)))); + } + + //===----------------------------------------------------------===// + // handle values of "u" that might be >= 10^2*N + // where N is the size of "u" in bytes + //===----------------------------------------------------------===// + + template + static inline char *itoa(char *p, UInt u) { + if (u < pow10>(N)) + return head(p, U(u)); + QR x = split(u); + return (u < pow10>(2 * N) ? (head(p, x)) : (large(p, x))); + } + + // selected when "u" is one byte + static inline char *itoa(char *p, U<1> u) { + if (u < 10) + return out(p, '0' + u); + if (u < 100) + return out(p, dd(u)); + return (D == Fwd ? (out(out(p, '0' + u / 100), dd(u % 100))) + : (out(out(p, dd(u % 100)), '0' + u / 100))); + } + + //===----------------------------------------------------------===// + // handle unsigned and signed integral operands + //===----------------------------------------------------------===// + + // itoa: handle unsigned integral operands (selected by SFINAE) + template ::value && + std::is_integral::value> * = nullptr> + static inline char *itoa(U u, char *p) { + return convert::template itoa(p, u); + } + + // itoa: handle signed integral operands (selected by SFINAE) + template ::value && + std::is_integral::value> * = nullptr> + static inline char *itoa(I i, char *p) { + // Need "mask" to be filled with a copy of the sign bit. + // If "i" is a negative value, then the result of "operator >>" + // is implementation-defined, though usually it is an arithmetic + // right shift that replicates the sign bit. + // Use a conditional expression to be portable, + // a good optimizing compiler generates an arithmetic right shift + // and avoids the conditional branch. + U mask = i < 0 ? ~U(0) : 0; + // Now get the absolute value of "i" and cast to unsigned type U. + // Cannot use std::abs() because the result is undefined + // in 2's complement systems for the most-negative value. + // Want to avoid conditional branch for performance reasons since + // CPU branch prediction will be ineffective when negative values + // occur randomly. + // Let "u" be "i" cast to unsigned type U. + // Subtract "u" from 2*u if "i" is positive or 0 if "i" is negative. + // This yields the absolute value with the desired type without + // using a conditional branch and without invoking undefined or + // implementation defined behavior: + U u = ((2 * U(i)) & ~mask) - U(i); + // Unconditionally store a minus sign when producing digits + // in a forward direction and increment the pointer only if + // the value is in fact negative. + // This avoids a conditional branch and is safe because we will + // always produce at least one digit and it will overwrite the + // minus sign when the value is not negative. + if (D == Fwd) { + *p = '-'; + p += (mask & 1); + } + p = convert::template itoa(p, u); + if (D == Rev && mask) + *--p = '-'; + return p; + } +}; +} // namespace dec_ + // Programming interface: itoa_fwd, itoa_rev -template char* itoa_fwd (I i,char *p) { - return dec_::convert::itoa(i,p); +template char *itoa_fwd(I i, char *p) { + return dec_::convert::itoa(i, p); } -static char * -xtoa (long long sval, - char * str, - int radix, - int signedp) -{ +static char *xtoa(long long sval, char *str, int radix, int signedp) { unsigned long long uval; unsigned int uradix = radix; char *sp = str; @@ -298,7 +287,7 @@ xtoa (long long sval, /* Mark end of string */ sp3 = sp; - *sp-- = 0; + *sp-- = 0; /* Reverse string contents (excluding sign) in place */ while (sp2 < sp) { @@ -310,8 +299,8 @@ xtoa (long long sval, return sp3; } -template char* itoa_rev (I i,char *p) { - return dec_::convert::itoa(i,p); +template char *itoa_rev(I i, char *p) { + return dec_::convert::itoa(i, p); } #endif // DEC_ITOA_IMPL_H diff --git a/include/cinatra/itoa_jeaiii.hpp b/include/cinatra/itoa_jeaiii.hpp index 9b83fc5..b579c75 100644 --- a/include/cinatra/itoa_jeaiii.hpp +++ b/include/cinatra/itoa_jeaiii.hpp @@ -26,18 +26,17 @@ SOFTWARE. #include // form a 4.32 fixed point number: t = u * 2^32 / 10^log10(u) -// use as much precision as possible when needed (log10(u) >= 5) +// use as much precision as possible when needed (log10(u) >= 5) // so shift up then down afterwards by log10(u) * log2(10) ~= 53/16 // need to round up before and or after in some cases -// once we have the fixed point number we can read off the digit in the upper 32 bits -// and multiply the lower 32 bits by 10 to get the next digit and so on -// we can do 2 digits at a time by multiplying by 100 each time +// once we have the fixed point number we can read off the digit in the upper 32 +// bits and multiply the lower 32 bits by 10 to get the next digit and so on we +// can do 2 digits at a time by multiplying by 100 each time // TODO: -// x64 optimized verison (no need to line up on 32bit boundary, so can multiply by 5 instead of 10 using lea instruction) -// full 64 bit LG() -// try splitting the number into chucks that can be processed independently -// try odd digit first +// x64 optimized verison (no need to line up on 32bit boundary, so can multiply +// by 5 instead of 10 using lea instruction) full 64 bit LG() try splitting the +// number into chucks that can be processed independently try odd digit first // try writing 4 chars at a time namespace cinatra { @@ -45,7 +44,10 @@ namespace cinatra { // 1 char at a time #define W(N, I) b[N] = char(I) + '0' -#define A(N) t = (uint64_t(1) << (32 + N / 5 * N * 53 / 16)) / uint32_t(1e##N) + 1 - N / 9, t *= u, t >>= N / 5 * N * 53 / 16, t += N / 5 * 4, W(0, t >> 32) +#define A(N) \ + t = (uint64_t(1) << (32 + N / 5 * N * 53 / 16)) / uint32_t(1e##N) + 1 - \ + N / 9, \ + t *= u, t >>= N / 5 * N * 53 / 16, t += N / 5 * 4, W(0, t >> 32) #define D(N) t = uint64_t(10) * uint32_t(t), W(N, t >> 32) #define L0 W(0, u) @@ -60,14 +62,22 @@ namespace cinatra { #define L9 A(9), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9) #else - // 2 chars at a time - - struct pair { char t, o; }; -#define CINATRAP(T) T, '0', T, '1', T, '2', T, '3', T, '4', T, '5', T, '6', T, '7', T, '8', T, '9' - static const pair s_pairs[] = { CINATRAP('0'), CINATRAP('1'), CINATRAP('2'), CINATRAP('3'), CINATRAP('4'), CINATRAP('5'), CINATRAP('6'), CINATRAP('7'), CINATRAP('8'), CINATRAP('9') }; - -#define CINATRAW(N, I) *(pair*)&b[N] = s_pairs[I] -#define CINATRAA(N) t = (uint64_t(1) << (32 + N / 5 * N * 53 / 16)) / uint32_t(1e##N) + 1 + N/6 - N/8, t *= u, t >>= N / 5 * N * 53 / 16, t += N / 6 * 4, CINATRAW(0, t >> 32) +// 2 chars at a time + +struct pair { + char t, o; +}; +#define CINATRAP(T) \ + T, '0', T, '1', T, '2', T, '3', T, '4', T, '5', T, '6', T, '7', T, '8', T, '9' +static const pair s_pairs[] = { + CINATRAP('0'), CINATRAP('1'), CINATRAP('2'), CINATRAP('3'), CINATRAP('4'), + CINATRAP('5'), CINATRAP('6'), CINATRAP('7'), CINATRAP('8'), CINATRAP('9')}; + +#define CINATRAW(N, I) *(pair *)&b[N] = s_pairs[I] +#define CINATRAA(N) \ + t = (uint64_t(1) << (32 + N / 5 * N * 53 / 16)) / uint32_t(1e##N) + 1 + \ + N / 6 - N / 8, \ + t *= u, t >>= N / 5 * N * 53 / 16, t += N / 6 * 4, CINATRAW(0, t >> 32) #define CINATRAS(N) b[N] = char(uint64_t(10) * uint32_t(t) >> 32) + '0' #define CINATRAD(N) t = uint64_t(100) * uint32_t(t), CINATRAW(N, t >> 32) @@ -79,55 +89,63 @@ namespace cinatra { #define CINATRAL5 CINATRAA(4), CINATRAD(2), CINATRAD(4) #define CINATRAL6 CINATRAA(5), CINATRAD(2), CINATRAD(4), CINATRAS(6) #define CINATRAL7 CINATRAA(6), CINATRAD(2), CINATRAD(4), CINATRAD(6) -#define CINATRAL8 CINATRAA(7), CINATRAD(2), CINATRAD(4), CINATRAD(6), CINATRAS(8) -#define CINATRAL9 CINATRAA(8), CINATRAD(2), CINATRAD(4), CINATRAD(6), CINATRAD(8) +#define CINATRAL8 \ + CINATRAA(7), CINATRAD(2), CINATRAD(4), CINATRAD(6), CINATRAS(8) +#define CINATRAL9 \ + CINATRAA(8), CINATRAD(2), CINATRAD(4), CINATRAD(6), CINATRAD(8) #endif #define LN(N) (CINATRAL##N, b += N + 1) #define LZ LN - // if you want to '\0' terminate - //#define LZ(N) &(L##N, b[N + 1] = '\0') - -#define LG(F) (u<100 ? u<10 ? F(0) : F(1) : u<1000000 ? u<10000 ? u<1000 ? F(2) : F(3) : u<100000 ? F(4) : F(5) : u<100000000 ? u<10000000 ? F(6) : F(7) : u<1000000000 ? F(8) : F(9)) - - inline char* u32toa_jeaiii(uint32_t u, char* b) { - uint64_t t; - return LG(LZ); - } - - inline char* i32toa_jeaiii(int32_t i, char* b) { - uint32_t u = i < 0 ? *b++ = '-', 0 - uint32_t(i) : i; - uint64_t t; - return LG(LZ); - } - - inline char* u64toa_jeaiii(uint64_t n, char* b) { - uint32_t u; - uint64_t t; - - if (uint32_t(n >> 32) == 0) - return u = uint32_t(n), LG(LZ); - - uint64_t a = n / 100000000; - - if (uint32_t(a >> 32) == 0) { - u = uint32_t(a); - LG(LN); - } - else { - u = uint32_t(a / 100000000); - LG(LN); - u = a % 100000000; - LN(7); - } - - u = n % 100000000; - return LZ(7); - } - - inline char* i64toa_jeaiii(int64_t i, char* b) { - uint64_t n = i < 0 ? *b++ = '-', 0 - uint64_t(i) : i; - return u64toa_jeaiii(n, b); - } +// if you want to '\0' terminate +//#define LZ(N) &(L##N, b[N + 1] = '\0') + +#define LG(F) \ + (u < 100 ? u < 10 ? F(0) : F(1) \ + : u < 1000000 ? u < 10000 ? u < 1000 ? F(2) : F(3) \ + : u < 100000 ? F(4) \ + : F(5) \ + : u < 100000000 ? u < 10000000 ? F(6) : F(7) \ + : u < 1000000000 ? F(8) \ + : F(9)) + +inline char *u32toa_jeaiii(uint32_t u, char *b) { + uint64_t t; + return LG(LZ); +} + +inline char *i32toa_jeaiii(int32_t i, char *b) { + uint32_t u = i < 0 ? *b++ = '-', 0 - uint32_t(i) : i; + uint64_t t; + return LG(LZ); +} + +inline char *u64toa_jeaiii(uint64_t n, char *b) { + uint32_t u; + uint64_t t; + + if (uint32_t(n >> 32) == 0) + return u = uint32_t(n), LG(LZ); + + uint64_t a = n / 100000000; + + if (uint32_t(a >> 32) == 0) { + u = uint32_t(a); + LG(LN); + } else { + u = uint32_t(a / 100000000); + LG(LN); + u = a % 100000000; + LN(7); + } + + u = n % 100000000; + return LZ(7); +} + +inline char *i64toa_jeaiii(int64_t i, char *b) { + uint64_t n = i < 0 ? *b++ = '-', 0 - uint64_t(i) : i; + return u64toa_jeaiii(n, b); } +} // namespace cinatra diff --git a/include/cinatra/mime_types.hpp b/include/cinatra/mime_types.hpp index 798c1e3..927114f 100644 --- a/include/cinatra/mime_types.hpp +++ b/include/cinatra/mime_types.hpp @@ -1,509 +1,511 @@ #pragma once -#include #include +#include namespace cinatra { - static const std::map mime_map ={ - { ".323", "text/h323" }, - { ".3gp", "video/3gpp" }, - { ".aab", "application/x-authoware-bin" }, - { ".aam", "application/x-authoware-map" }, - { ".aas", "application/x-authoware-seg" }, - { ".acx", "application/internet-property-stream" }, - { ".ai", "application/postscript" }, - { ".aif", "audio/x-aiff" }, - { ".aifc", "audio/x-aiff" }, - { ".aiff", "audio/x-aiff" }, - { ".als", "audio/X-Alpha5" }, - { ".amc", "application/x-mpeg" }, - { ".ani", "application/octet-stream" }, - { ".apk", "application/vnd.android.package-archive" }, - { ".asc", "text/plain" }, - { ".asd", "application/astound" }, - { ".asf", "video/x-ms-asf" }, - { ".asn", "application/astound" }, - { ".asp", "application/x-asap" }, - { ".asr", "video/x-ms-asf" }, - { ".asx", "video/x-ms-asf" }, - { ".au", "audio/basic" }, - { ".avb", "application/octet-stream" }, - { ".avi", "video/x-msvideo" }, - { ".awb", "audio/amr-wb" }, - { ".axs", "application/olescript" }, - { ".bas", "text/plain" }, - { ".bcpio", "application/x-bcpio" }, - { ".bin ", "application/octet-stream" }, - { ".bld", "application/bld" }, - { ".bld2", "application/bld2" }, - { ".bmp", "image/bmp" }, - { ".bpk", "application/octet-stream" }, - { ".bz2", "application/x-bzip2" }, - { ".c", "text/plain" }, - { ".cal", "image/x-cals" }, - { ".cat", "application/vnd.ms-pkiseccat" }, - { ".ccn", "application/x-cnc" }, - { ".cco", "application/x-cocoa" }, - { ".cdf", "application/x-cdf" }, - { ".cer", "application/x-x509-ca-cert" }, - { ".cgi", "magnus-internal/cgi" }, - { ".chat", "application/x-chat" }, - { ".class", "application/octet-stream" }, - { ".clp", "application/x-msclip" }, - { ".cmx", "image/x-cmx" }, - { ".co", "application/x-cult3d-object" }, - { ".cod", "image/cis-cod" }, - { ".conf", "text/plain" }, - { ".cpio", "application/x-cpio" }, - { ".cpp", "text/plain" }, - { ".cpt", "application/mac-compactpro" }, - { ".crd", "application/x-mscardfile" }, - { ".crl", "application/pkix-crl" }, - { ".crt", "application/x-x509-ca-cert" }, - { ".csh", "application/x-csh" }, - { ".csm", "chemical/x-csml" }, - { ".csml", "chemical/x-csml" }, - { ".css", "text/css" }, - { ".cur", "application/octet-stream" }, - { ".dcm", "x-lml/x-evm" }, - { ".dcr", "application/x-director" }, - { ".dcx", "image/x-dcx" }, - { ".der", "application/x-x509-ca-cert" }, - { ".dhtml", "text/html" }, - { ".dir", "application/x-director" }, - { ".dll", "application/x-msdownload" }, - { ".dmg", "application/octet-stream" }, - { ".dms", "application/octet-stream" }, - { ".doc", "application/msword" }, - { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, - { ".dot", "application/msword" }, - { ".dvi", "application/x-dvi" }, - { ".dwf", "drawing/x-dwf" }, - { ".dwg", "application/x-autocad" }, - { ".dxf", "application/x-autocad" }, - { ".dxr", "application/x-director" }, - { ".ebk", "application/x-expandedbook" }, - { ".emb", "chemical/x-embl-dl-nucleotide" }, - { ".embl", "chemical/x-embl-dl-nucleotide" }, - { ".eps", "application/postscript" }, - { ".epub", "application/epub+zip" }, - { ".eri", "image/x-eri" }, - { ".es", "audio/echospeech" }, - { ".esl", "audio/echospeech" }, - { ".etc", "application/x-earthtime" }, - { ".etx", "text/x-setext" }, - { ".evm", "x-lml/x-evm" }, - { ".evy", "application/envoy" }, - { ".exe", "application/octet-stream" }, - { ".fh4", "image/x-freehand" }, - { ".fh5", "image/x-freehand" }, - { ".fhc", "image/x-freehand" }, - { ".fif", "application/fractals" }, - { ".flr", "x-world/x-vrml" }, - { ".flv", "flv-application/octet-stream" }, - { ".fm", "application/x-maker" }, - { ".fpx", "image/x-fpx" }, - { ".fvi", "video/isivideo" }, - { ".gau", "chemical/x-gaussian-input" }, - { ".gca", "application/x-gca-compressed" }, - { ".gdb", "x-lml/x-gdb" }, - { ".gif", "image/gif" }, - { ".gps", "application/x-gps" }, - { ".gtar", "application/x-gtar" }, - { ".gz", "application/x-gzip" }, - { ".h", "text/plain" }, - { ".hdf", "application/x-hdf" }, - { ".hdm", "text/x-hdml" }, - { ".hdml", "text/x-hdml" }, - { ".hlp", "application/winhlp" }, - { ".hqx", "application/mac-binhex40" }, - { ".hta", "application/hta" }, - { ".htc", "text/x-component" }, - { ".htm", "text/html" }, - { ".html", "text/html" }, - { ".hts", "text/html" }, - { ".htt", "text/webviewhtml" }, - { ".ice", "x-conference/x-cooltalk" }, - { ".ico", "image/x-icon" }, - { ".ief", "image/ief" }, - { ".ifm", "image/gif" }, - { ".ifs", "image/ifs" }, - { ".iii", "application/x-iphone" }, - { ".imy", "audio/melody" }, - { ".ins", "application/x-internet-signup" }, - { ".ips", "application/x-ipscript" }, - { ".ipx", "application/x-ipix" }, - { ".isp", "application/x-internet-signup" }, - { ".it", "audio/x-mod" }, - { ".itz", "audio/x-mod" }, - { ".ivr", "i-world/i-vrml" }, - { ".j2k", "image/j2k" }, - { ".jad", "text/vnd.sun.j2me.app-descriptor" }, - { ".jam", "application/x-jam" }, - { ".jar", "application/java-archive" }, - { ".java", "text/plain" }, - { ".jfif", "image/pipeg" }, - { ".jnlp", "application/x-java-jnlp-file" }, - { ".jpe", "image/jpeg" }, - { ".jpeg", "image/jpeg" }, - { ".jpg", "image/jpeg" }, - { ".jpz", "image/jpeg" }, - { ".js", "application/x-javascript" }, - { ".jwc", "application/jwc" }, - { ".kjx", "application/x-kjx" }, - { ".lak", "x-lml/x-lak" }, - { ".latex", "application/x-latex" }, - { ".lcc", "application/fastman" }, - { ".lcl", "application/x-digitalloca" }, - { ".lcr", "application/x-digitalloca" }, - { ".lgh", "application/lgh" }, - { ".lha", "application/octet-stream" }, - { ".lml", "x-lml/x-lml" }, - { ".lmlpack", "x-lml/x-lmlpack" }, - { ".log", "text/plain" }, - { ".lsf", "video/x-la-asf" }, - { ".lsx", "video/x-la-asf" }, - { ".lzh", "application/octet-stream" }, - { ".m13", "application/x-msmediaview" }, - { ".m14", "application/x-msmediaview" }, - { ".m15", "audio/x-mod" }, - { ".m3u", "audio/x-mpegurl" }, - { ".m3url", "audio/x-mpegurl" }, - { ".m4a", "audio/mp4a-latm" }, - { ".m4b", "audio/mp4a-latm" }, - { ".m4p", "audio/mp4a-latm" }, - { ".m4u", "video/vnd.mpegurl" }, - { ".m4v", "video/x-m4v" }, - { ".ma1", "audio/ma1" }, - { ".ma2", "audio/ma2" }, - { ".ma3", "audio/ma3" }, - { ".ma5", "audio/ma5" }, - { ".man", "application/x-troff-man" }, - { ".map", "magnus-internal/imagemap" }, - { ".mbd", "application/mbedlet" }, - { ".mct", "application/x-mascot" }, - { ".mdb", "application/x-msaccess" }, - { ".mdz", "audio/x-mod" }, - { ".me", "application/x-troff-me" }, - { ".mel", "text/x-vmel" }, - { ".mht", "message/rfc822" }, - { ".mhtml", "message/rfc822" }, - { ".mi", "application/x-mif" }, - { ".mid", "audio/mid" }, - { ".midi", "audio/midi" }, - { ".mif", "application/x-mif" }, - { ".mil", "image/x-cals" }, - { ".mio", "audio/x-mio" }, - { ".mmf", "application/x-skt-lbs" }, - { ".mng", "video/x-mng" }, - { ".mny", "application/x-msmoney" }, - { ".moc", "application/x-mocha" }, - { ".mocha", "application/x-mocha" }, - { ".mod", "audio/x-mod" }, - { ".mof", "application/x-yumekara" }, - { ".mol", "chemical/x-mdl-molfile" }, - { ".mop", "chemical/x-mopac-input" }, - { ".mov", "video/quicktime" }, - { ".movie", "video/x-sgi-movie" }, - { ".mp2", "video/mpeg" }, - { ".mp3", "audio/mpeg" }, - { ".mp4", "video/mp4" }, - { ".mpa", "video/mpeg" }, - { ".mpc", "application/vnd.mpohun.certificate" }, - { ".mpe", "video/mpeg" }, - { ".mpeg", "video/mpeg" }, - { ".mpg", "video/mpeg" }, - { ".mpg4", "video/mp4" }, - { ".mpga", "audio/mpeg" }, - { ".mpn", "application/vnd.mophun.application" }, - { ".mpp", "application/vnd.ms-project" }, - { ".mps", "application/x-mapserver" }, - { ".mpv2", "video/mpeg" }, - { ".mrl", "text/x-mrml" }, - { ".mrm", "application/x-mrm" }, - { ".ms", "application/x-troff-ms" }, - { ".msg", "application/vnd.ms-outlook" }, - { ".mts", "application/metastream" }, - { ".mtx", "application/metastream" }, - { ".mtz", "application/metastream" }, - { ".mvb", "application/x-msmediaview" }, - { ".mzv", "application/metastream" }, - { ".nar", "application/zip" }, - { ".nbmp", "image/nbmp" }, - { ".nc", "application/x-netcdf" }, - { ".ndb", "x-lml/x-ndb" }, - { ".ndwn", "application/ndwn" }, - { ".nif", "application/x-nif" }, - { ".nmz", "application/x-scream" }, - { ".nokia-op-logo", "image/vnd.nok-oplogo-color" }, - { ".npx", "application/x-netfpx" }, - { ".nsnd", "audio/nsnd" }, - { ".nva", "application/x-neva1" }, - { ".nws", "message/rfc822" }, - { ".oda", "application/oda" }, - { ".ogg", "audio/ogg" }, - { ".oom", "application/x-AtlasMate-Plugin" }, - { ".p10", "application/pkcs10" }, - { ".p12", "application/x-pkcs12" }, - { ".p7b", "application/x-pkcs7-certificates" }, - { ".p7c", "application/x-pkcs7-mime" }, - { ".p7m", "application/x-pkcs7-mime" }, - { ".p7r", "application/x-pkcs7-certreqresp" }, - { ".p7s", "application/x-pkcs7-signature" }, - { ".pac", "audio/x-pac" }, - { ".pae", "audio/x-epac" }, - { ".pan", "application/x-pan" }, - { ".pbm", "image/x-portable-bitmap" }, - { ".pcx", "image/x-pcx" }, - { ".pda", "image/x-pda" }, - { ".pdb", "chemical/x-pdb" }, - { ".pdf", "application/pdf" }, - { ".pfr", "application/font-tdpfr" }, - { ".pfx", "application/x-pkcs12" }, - { ".pgm", "image/x-portable-graymap" }, - { ".pict", "image/x-pict" }, - { ".pko", "application/ynd.ms-pkipko" }, - { ".pm", "application/x-perl" }, - { ".pma", "application/x-perfmon" }, - { ".pmc", "application/x-perfmon" }, - { ".pmd", "application/x-pmd" }, - { ".pml", "application/x-perfmon" }, - { ".pmr", "application/x-perfmon" }, - { ".pmw", "application/x-perfmon" }, - { ".png", "image/png" }, - { ".pnm", "image/x-portable-anymap" }, - { ".pnz", "image/png" }, - { ".pot,", "application/vnd.ms-powerpoint" }, - { ".ppm", "image/x-portable-pixmap" }, - { ".pps", "application/vnd.ms-powerpoint" }, - { ".ppt", "application/vnd.ms-powerpoint" }, - { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, - { ".pqf", "application/x-cprplayer" }, - { ".pqi", "application/cprplayer" }, - { ".prc", "application/x-prc" }, - { ".prf", "application/pics-rules" }, - { ".prop", "text/plain" }, - { ".proxy", "application/x-ns-proxy-autoconfig" }, - { ".ps", "application/postscript" }, - { ".ptlk", "application/listenup" }, - { ".pub", "application/x-mspublisher" }, - { ".pvx", "video/x-pv-pvx" }, - { ".qcp", "audio/vnd.qcelp" }, - { ".qt", "video/quicktime" }, - { ".qti", "image/x-quicktime" }, - { ".qtif", "image/x-quicktime" }, - { ".r3t", "text/vnd.rn-realtext3d" }, - { ".ra", "audio/x-pn-realaudio" }, - { ".ram", "audio/x-pn-realaudio" }, - { ".rar", "application/octet-stream" }, - { ".ras", "image/x-cmu-raster" }, - { ".rc", "text/plain" }, - { ".rdf", "application/rdf+xml" }, - { ".rf", "image/vnd.rn-realflash" }, - { ".rgb", "image/x-rgb" }, - { ".rlf", "application/x-richlink" }, - { ".rm", "audio/x-pn-realaudio" }, - { ".rmf", "audio/x-rmf" }, - { ".rmi", "audio/mid" }, - { ".rmm", "audio/x-pn-realaudio" }, - { ".rmvb", "audio/x-pn-realaudio" }, - { ".rnx", "application/vnd.rn-realplayer" }, - { ".roff", "application/x-troff" }, - { ".rp", "image/vnd.rn-realpix" }, - { ".rpm", "audio/x-pn-realaudio-plugin" }, - { ".rt", "text/vnd.rn-realtext" }, - { ".rte", "x-lml/x-gps" }, - { ".rtf", "application/rtf" }, - { ".rtg", "application/metastream" }, - { ".rtx", "text/richtext" }, - { ".rv", "video/vnd.rn-realvideo" }, - { ".rwc", "application/x-rogerwilco" }, - { ".s3m", "audio/x-mod" }, - { ".s3z", "audio/x-mod" }, - { ".sca", "application/x-supercard" }, - { ".scd", "application/x-msschedule" }, - { ".sct", "text/scriptlet" }, - { ".sdf", "application/e-score" }, - { ".sea", "application/x-stuffit" }, - { ".setpay", "application/set-payment-initiation" }, - { ".setreg", "application/set-registration-initiation" }, - { ".sgm", "text/x-sgml" }, - { ".sgml", "text/x-sgml" }, - { ".sh", "application/x-sh" }, - { ".shar", "application/x-shar" }, - { ".shtml", "magnus-internal/parsed-html" }, - { ".shw", "application/presentations" }, - { ".si6", "image/si6" }, - { ".si7", "image/vnd.stiwap.sis" }, - { ".si9", "image/vnd.lgtwap.sis" }, - { ".sis", "application/vnd.symbian.install" }, - { ".sit", "application/x-stuffit" }, - { ".skd", "application/x-Koan" }, - { ".skm", "application/x-Koan" }, - { ".skp", "application/x-Koan" }, - { ".skt", "application/x-Koan" }, - { ".slc", "application/x-salsa" }, - { ".smd", "audio/x-smd" }, - { ".smi", "application/smil" }, - { ".smil", "application/smil" }, - { ".smp", "application/studiom" }, - { ".smz", "audio/x-smd" }, - { ".snd", "audio/basic" }, - { ".spc", "application/x-pkcs7-certificates" }, - { ".spl", "application/futuresplash" }, - { ".spr", "application/x-sprite" }, - { ".sprite", "application/x-sprite" }, - { ".sdp", "application/sdp" }, - { ".spt", "application/x-spt" }, - { ".src", "application/x-wais-source" }, - { ".sst", "application/vnd.ms-pkicertstore" }, - { ".stk", "application/hyperstudio" }, - { ".stl", "application/vnd.ms-pkistl" }, - { ".stm", "text/html" }, - { ".svg", "image/svg+xml" }, - { ".sv4cpio", "application/x-sv4cpio" }, - { ".sv4crc", "application/x-sv4crc" }, - { ".svf", "image/vnd" }, - { ".eot", "application/vnd.ms-fontobject" }, - { ".woff", "application/font-woff" }, - { ".svh", "image/svh" }, - { ".svr", "x-world/x-svr" }, - { ".swf", "application/x-shockwave-flash" }, - { ".swfl", "application/x-shockwave-flash" }, - { ".t", "application/x-troff" }, - { ".tad", "application/octet-stream" }, - { ".talk", "text/x-speech" }, - { ".tar", "application/x-tar" }, - { ".taz", "application/x-tar" }, - { ".tbp", "application/x-timbuktu" }, - { ".tbt", "application/x-timbuktu" }, - { ".tcl", "application/x-tcl" }, - { ".tex", "application/x-tex" }, - { ".texi", "application/x-texinfo" }, - { ".texinfo", "application/x-texinfo" }, - { ".tgz", "application/x-compressed" }, - { ".thm", "application/vnd.eri.thm" }, - { ".tif", "image/tiff" }, - { ".tiff", "image/tiff" }, - { ".tki", "application/x-tkined" }, - { ".tkined", "application/x-tkined" }, - { ".toc", "application/toc" }, - { ".toy", "image/toy" }, - { ".tr", "application/x-troff" }, - { ".trk", "x-lml/x-gps" }, - { ".trm", "application/x-msterminal" }, - { ".tsi", "audio/tsplayer" }, - { ".tsp", "application/dsptype" }, - { ".tsv", "text/tab-separated-values" }, - { ".ttf", "application/octet-stream" }, - { ".ttz", "application/t-time" }, - { ".txt", "text/plain" }, - { ".uls", "text/iuls" }, - { ".ult", "audio/x-mod" }, - { ".ustar", "application/x-ustar" }, - { ".uu", "application/x-uuencode" }, - { ".uue", "application/x-uuencode" }, - { ".vcd", "application/x-cdlink" }, - { ".vcf", "text/x-vcard" }, - { ".vdo", "video/vdo" }, - { ".vib", "audio/vib" }, - { ".viv", "video/vivo" }, - { ".vivo", "video/vivo" }, - { ".vmd", "application/vocaltec-media-desc" }, - { ".vmf", "application/vocaltec-media-file" }, - { ".vmi", "application/x-dreamcast-vms-info" }, - { ".vms", "application/x-dreamcast-vms" }, - { ".vox", "audio/voxware" }, - { ".vqe", "audio/x-twinvq-plugin" }, - { ".vqf", "audio/x-twinvq" }, - { ".vql", "audio/x-twinvq" }, - { ".vre", "x-world/x-vream" }, - { ".vrml", "x-world/x-vrml" }, - { ".vrt", "x-world/x-vrt" }, - { ".vrw", "x-world/x-vream" }, - { ".vts", "workbook/formulaone" }, - { ".wav", "audio/x-wav" }, - { ".wax", "audio/x-ms-wax" }, - { ".wbmp", "image/vnd.wap.wbmp" }, - { ".wcm", "application/vnd.ms-works" }, - { ".wdb", "application/vnd.ms-works" }, - { ".web", "application/vnd.xara" }, - { ".wi", "image/wavelet" }, - { ".wis", "application/x-InstallShield" }, - { ".wks", "application/vnd.ms-works" }, - { ".wm", "video/x-ms-wm" }, - { ".wma", "audio/x-ms-wma" }, - { ".wmd", "application/x-ms-wmd" }, - { ".wmf", "application/x-msmetafile" }, - { ".wml", "text/vnd.wap.wml" }, - { ".wmlc", "application/vnd.wap.wmlc" }, - { ".wmls", "text/vnd.wap.wmlscript" }, - { ".wmlsc", "application/vnd.wap.wmlscriptc" }, - { ".wmlscript", "text/vnd.wap.wmlscript" }, - { ".wmv", "audio/x-ms-wmv" }, - { ".wmx", "video/x-ms-wmx" }, - { ".wmz", "application/x-ms-wmz" }, - { ".wpng", "image/x-up-wpng" }, - { ".wps", "application/vnd.ms-works" }, - { ".wpt", "x-lml/x-gps" }, - { ".wri", "application/x-mswrite" }, - { ".wrl", "x-world/x-vrml" }, - { ".wrz", "x-world/x-vrml" }, - { ".ws", "text/vnd.wap.wmlscript" }, - { ".wsc", "application/vnd.wap.wmlscriptc" }, - { ".wv", "video/wavelet" }, - { ".wvx", "video/x-ms-wvx" }, - { ".wxl", "application/x-wxl" }, - { ".x-gzip", "application/x-gzip" }, - { ".xaf", "x-world/x-vrml" }, - { ".xar", "application/vnd.xara" }, - { ".xbm", "image/x-xbitmap" }, - { ".xdm", "application/x-xdma" }, - { ".xdma", "application/x-xdma" }, - { ".xdw", "application/vnd.fujixerox.docuworks" }, - { ".xht", "application/xhtml+xml" }, - { ".xhtm", "application/xhtml+xml" }, - { ".xhtml", "application/xhtml+xml" }, - { ".xla", "application/vnd.ms-excel" }, - { ".xlc", "application/vnd.ms-excel" }, - { ".xll", "application/x-excel" }, - { ".xlm", "application/vnd.ms-excel" }, - { ".xls", "application/vnd.ms-excel" }, - { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, - { ".xlt", "application/vnd.ms-excel" }, - { ".xlw", "application/vnd.ms-excel" }, - { ".xm", "audio/x-mod" }, - { ".xml","text/plain" }, - { ".xml","application/xml" }, - { ".xmz", "audio/x-mod" }, - { ".xof", "x-world/x-vrml" }, - { ".xpi", "application/x-xpinstall" }, - { ".xpm", "image/x-xpixmap" }, - { ".xsit", "text/xml" }, - { ".xsl", "text/xml" }, - { ".xul", "text/xul" }, - { ".xwd", "image/x-xwindowdump" }, - { ".xyz", "chemical/x-pdb" }, - { ".yz1", "application/x-yz1" }, - { ".z", "application/x-compress" }, - { ".zac", "application/x-zaurus-zac" }, - { ".zip", "application/zip" }, - { ".json", "application/json" }, - { ".7z", "application/x-7z-compressed" }, - }; +static const std::map mime_map = { + {".323", "text/h323"}, + {".3gp", "video/3gpp"}, + {".aab", "application/x-authoware-bin"}, + {".aam", "application/x-authoware-map"}, + {".aas", "application/x-authoware-seg"}, + {".acx", "application/internet-property-stream"}, + {".ai", "application/postscript"}, + {".aif", "audio/x-aiff"}, + {".aifc", "audio/x-aiff"}, + {".aiff", "audio/x-aiff"}, + {".als", "audio/X-Alpha5"}, + {".amc", "application/x-mpeg"}, + {".ani", "application/octet-stream"}, + {".apk", "application/vnd.android.package-archive"}, + {".asc", "text/plain"}, + {".asd", "application/astound"}, + {".asf", "video/x-ms-asf"}, + {".asn", "application/astound"}, + {".asp", "application/x-asap"}, + {".asr", "video/x-ms-asf"}, + {".asx", "video/x-ms-asf"}, + {".au", "audio/basic"}, + {".avb", "application/octet-stream"}, + {".avi", "video/x-msvideo"}, + {".awb", "audio/amr-wb"}, + {".axs", "application/olescript"}, + {".bas", "text/plain"}, + {".bcpio", "application/x-bcpio"}, + {".bin ", "application/octet-stream"}, + {".bld", "application/bld"}, + {".bld2", "application/bld2"}, + {".bmp", "image/bmp"}, + {".bpk", "application/octet-stream"}, + {".bz2", "application/x-bzip2"}, + {".c", "text/plain"}, + {".cal", "image/x-cals"}, + {".cat", "application/vnd.ms-pkiseccat"}, + {".ccn", "application/x-cnc"}, + {".cco", "application/x-cocoa"}, + {".cdf", "application/x-cdf"}, + {".cer", "application/x-x509-ca-cert"}, + {".cgi", "magnus-internal/cgi"}, + {".chat", "application/x-chat"}, + {".class", "application/octet-stream"}, + {".clp", "application/x-msclip"}, + {".cmx", "image/x-cmx"}, + {".co", "application/x-cult3d-object"}, + {".cod", "image/cis-cod"}, + {".conf", "text/plain"}, + {".cpio", "application/x-cpio"}, + {".cpp", "text/plain"}, + {".cpt", "application/mac-compactpro"}, + {".crd", "application/x-mscardfile"}, + {".crl", "application/pkix-crl"}, + {".crt", "application/x-x509-ca-cert"}, + {".csh", "application/x-csh"}, + {".csm", "chemical/x-csml"}, + {".csml", "chemical/x-csml"}, + {".css", "text/css"}, + {".cur", "application/octet-stream"}, + {".dcm", "x-lml/x-evm"}, + {".dcr", "application/x-director"}, + {".dcx", "image/x-dcx"}, + {".der", "application/x-x509-ca-cert"}, + {".dhtml", "text/html"}, + {".dir", "application/x-director"}, + {".dll", "application/x-msdownload"}, + {".dmg", "application/octet-stream"}, + {".dms", "application/octet-stream"}, + {".doc", "application/msword"}, + {".docx", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {".dot", "application/msword"}, + {".dvi", "application/x-dvi"}, + {".dwf", "drawing/x-dwf"}, + {".dwg", "application/x-autocad"}, + {".dxf", "application/x-autocad"}, + {".dxr", "application/x-director"}, + {".ebk", "application/x-expandedbook"}, + {".emb", "chemical/x-embl-dl-nucleotide"}, + {".embl", "chemical/x-embl-dl-nucleotide"}, + {".eps", "application/postscript"}, + {".epub", "application/epub+zip"}, + {".eri", "image/x-eri"}, + {".es", "audio/echospeech"}, + {".esl", "audio/echospeech"}, + {".etc", "application/x-earthtime"}, + {".etx", "text/x-setext"}, + {".evm", "x-lml/x-evm"}, + {".evy", "application/envoy"}, + {".exe", "application/octet-stream"}, + {".fh4", "image/x-freehand"}, + {".fh5", "image/x-freehand"}, + {".fhc", "image/x-freehand"}, + {".fif", "application/fractals"}, + {".flr", "x-world/x-vrml"}, + {".flv", "flv-application/octet-stream"}, + {".fm", "application/x-maker"}, + {".fpx", "image/x-fpx"}, + {".fvi", "video/isivideo"}, + {".gau", "chemical/x-gaussian-input"}, + {".gca", "application/x-gca-compressed"}, + {".gdb", "x-lml/x-gdb"}, + {".gif", "image/gif"}, + {".gps", "application/x-gps"}, + {".gtar", "application/x-gtar"}, + {".gz", "application/x-gzip"}, + {".h", "text/plain"}, + {".hdf", "application/x-hdf"}, + {".hdm", "text/x-hdml"}, + {".hdml", "text/x-hdml"}, + {".hlp", "application/winhlp"}, + {".hqx", "application/mac-binhex40"}, + {".hta", "application/hta"}, + {".htc", "text/x-component"}, + {".htm", "text/html"}, + {".html", "text/html"}, + {".hts", "text/html"}, + {".htt", "text/webviewhtml"}, + {".ice", "x-conference/x-cooltalk"}, + {".ico", "image/x-icon"}, + {".ief", "image/ief"}, + {".ifm", "image/gif"}, + {".ifs", "image/ifs"}, + {".iii", "application/x-iphone"}, + {".imy", "audio/melody"}, + {".ins", "application/x-internet-signup"}, + {".ips", "application/x-ipscript"}, + {".ipx", "application/x-ipix"}, + {".isp", "application/x-internet-signup"}, + {".it", "audio/x-mod"}, + {".itz", "audio/x-mod"}, + {".ivr", "i-world/i-vrml"}, + {".j2k", "image/j2k"}, + {".jad", "text/vnd.sun.j2me.app-descriptor"}, + {".jam", "application/x-jam"}, + {".jar", "application/java-archive"}, + {".java", "text/plain"}, + {".jfif", "image/pipeg"}, + {".jnlp", "application/x-java-jnlp-file"}, + {".jpe", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".jpg", "image/jpeg"}, + {".jpz", "image/jpeg"}, + {".js", "application/x-javascript"}, + {".jwc", "application/jwc"}, + {".kjx", "application/x-kjx"}, + {".lak", "x-lml/x-lak"}, + {".latex", "application/x-latex"}, + {".lcc", "application/fastman"}, + {".lcl", "application/x-digitalloca"}, + {".lcr", "application/x-digitalloca"}, + {".lgh", "application/lgh"}, + {".lha", "application/octet-stream"}, + {".lml", "x-lml/x-lml"}, + {".lmlpack", "x-lml/x-lmlpack"}, + {".log", "text/plain"}, + {".lsf", "video/x-la-asf"}, + {".lsx", "video/x-la-asf"}, + {".lzh", "application/octet-stream"}, + {".m13", "application/x-msmediaview"}, + {".m14", "application/x-msmediaview"}, + {".m15", "audio/x-mod"}, + {".m3u", "audio/x-mpegurl"}, + {".m3url", "audio/x-mpegurl"}, + {".m4a", "audio/mp4a-latm"}, + {".m4b", "audio/mp4a-latm"}, + {".m4p", "audio/mp4a-latm"}, + {".m4u", "video/vnd.mpegurl"}, + {".m4v", "video/x-m4v"}, + {".ma1", "audio/ma1"}, + {".ma2", "audio/ma2"}, + {".ma3", "audio/ma3"}, + {".ma5", "audio/ma5"}, + {".man", "application/x-troff-man"}, + {".map", "magnus-internal/imagemap"}, + {".mbd", "application/mbedlet"}, + {".mct", "application/x-mascot"}, + {".mdb", "application/x-msaccess"}, + {".mdz", "audio/x-mod"}, + {".me", "application/x-troff-me"}, + {".mel", "text/x-vmel"}, + {".mht", "message/rfc822"}, + {".mhtml", "message/rfc822"}, + {".mi", "application/x-mif"}, + {".mid", "audio/mid"}, + {".midi", "audio/midi"}, + {".mif", "application/x-mif"}, + {".mil", "image/x-cals"}, + {".mio", "audio/x-mio"}, + {".mmf", "application/x-skt-lbs"}, + {".mng", "video/x-mng"}, + {".mny", "application/x-msmoney"}, + {".moc", "application/x-mocha"}, + {".mocha", "application/x-mocha"}, + {".mod", "audio/x-mod"}, + {".mof", "application/x-yumekara"}, + {".mol", "chemical/x-mdl-molfile"}, + {".mop", "chemical/x-mopac-input"}, + {".mov", "video/quicktime"}, + {".movie", "video/x-sgi-movie"}, + {".mp2", "video/mpeg"}, + {".mp3", "audio/mpeg"}, + {".mp4", "video/mp4"}, + {".mpa", "video/mpeg"}, + {".mpc", "application/vnd.mpohun.certificate"}, + {".mpe", "video/mpeg"}, + {".mpeg", "video/mpeg"}, + {".mpg", "video/mpeg"}, + {".mpg4", "video/mp4"}, + {".mpga", "audio/mpeg"}, + {".mpn", "application/vnd.mophun.application"}, + {".mpp", "application/vnd.ms-project"}, + {".mps", "application/x-mapserver"}, + {".mpv2", "video/mpeg"}, + {".mrl", "text/x-mrml"}, + {".mrm", "application/x-mrm"}, + {".ms", "application/x-troff-ms"}, + {".msg", "application/vnd.ms-outlook"}, + {".mts", "application/metastream"}, + {".mtx", "application/metastream"}, + {".mtz", "application/metastream"}, + {".mvb", "application/x-msmediaview"}, + {".mzv", "application/metastream"}, + {".nar", "application/zip"}, + {".nbmp", "image/nbmp"}, + {".nc", "application/x-netcdf"}, + {".ndb", "x-lml/x-ndb"}, + {".ndwn", "application/ndwn"}, + {".nif", "application/x-nif"}, + {".nmz", "application/x-scream"}, + {".nokia-op-logo", "image/vnd.nok-oplogo-color"}, + {".npx", "application/x-netfpx"}, + {".nsnd", "audio/nsnd"}, + {".nva", "application/x-neva1"}, + {".nws", "message/rfc822"}, + {".oda", "application/oda"}, + {".ogg", "audio/ogg"}, + {".oom", "application/x-AtlasMate-Plugin"}, + {".p10", "application/pkcs10"}, + {".p12", "application/x-pkcs12"}, + {".p7b", "application/x-pkcs7-certificates"}, + {".p7c", "application/x-pkcs7-mime"}, + {".p7m", "application/x-pkcs7-mime"}, + {".p7r", "application/x-pkcs7-certreqresp"}, + {".p7s", "application/x-pkcs7-signature"}, + {".pac", "audio/x-pac"}, + {".pae", "audio/x-epac"}, + {".pan", "application/x-pan"}, + {".pbm", "image/x-portable-bitmap"}, + {".pcx", "image/x-pcx"}, + {".pda", "image/x-pda"}, + {".pdb", "chemical/x-pdb"}, + {".pdf", "application/pdf"}, + {".pfr", "application/font-tdpfr"}, + {".pfx", "application/x-pkcs12"}, + {".pgm", "image/x-portable-graymap"}, + {".pict", "image/x-pict"}, + {".pko", "application/ynd.ms-pkipko"}, + {".pm", "application/x-perl"}, + {".pma", "application/x-perfmon"}, + {".pmc", "application/x-perfmon"}, + {".pmd", "application/x-pmd"}, + {".pml", "application/x-perfmon"}, + {".pmr", "application/x-perfmon"}, + {".pmw", "application/x-perfmon"}, + {".png", "image/png"}, + {".pnm", "image/x-portable-anymap"}, + {".pnz", "image/png"}, + {".pot,", "application/vnd.ms-powerpoint"}, + {".ppm", "image/x-portable-pixmap"}, + {".pps", "application/vnd.ms-powerpoint"}, + {".ppt", "application/vnd.ms-powerpoint"}, + {".pptx", "application/" + "vnd.openxmlformats-officedocument.presentationml.presentation"}, + {".pqf", "application/x-cprplayer"}, + {".pqi", "application/cprplayer"}, + {".prc", "application/x-prc"}, + {".prf", "application/pics-rules"}, + {".prop", "text/plain"}, + {".proxy", "application/x-ns-proxy-autoconfig"}, + {".ps", "application/postscript"}, + {".ptlk", "application/listenup"}, + {".pub", "application/x-mspublisher"}, + {".pvx", "video/x-pv-pvx"}, + {".qcp", "audio/vnd.qcelp"}, + {".qt", "video/quicktime"}, + {".qti", "image/x-quicktime"}, + {".qtif", "image/x-quicktime"}, + {".r3t", "text/vnd.rn-realtext3d"}, + {".ra", "audio/x-pn-realaudio"}, + {".ram", "audio/x-pn-realaudio"}, + {".rar", "application/octet-stream"}, + {".ras", "image/x-cmu-raster"}, + {".rc", "text/plain"}, + {".rdf", "application/rdf+xml"}, + {".rf", "image/vnd.rn-realflash"}, + {".rgb", "image/x-rgb"}, + {".rlf", "application/x-richlink"}, + {".rm", "audio/x-pn-realaudio"}, + {".rmf", "audio/x-rmf"}, + {".rmi", "audio/mid"}, + {".rmm", "audio/x-pn-realaudio"}, + {".rmvb", "audio/x-pn-realaudio"}, + {".rnx", "application/vnd.rn-realplayer"}, + {".roff", "application/x-troff"}, + {".rp", "image/vnd.rn-realpix"}, + {".rpm", "audio/x-pn-realaudio-plugin"}, + {".rt", "text/vnd.rn-realtext"}, + {".rte", "x-lml/x-gps"}, + {".rtf", "application/rtf"}, + {".rtg", "application/metastream"}, + {".rtx", "text/richtext"}, + {".rv", "video/vnd.rn-realvideo"}, + {".rwc", "application/x-rogerwilco"}, + {".s3m", "audio/x-mod"}, + {".s3z", "audio/x-mod"}, + {".sca", "application/x-supercard"}, + {".scd", "application/x-msschedule"}, + {".sct", "text/scriptlet"}, + {".sdf", "application/e-score"}, + {".sea", "application/x-stuffit"}, + {".setpay", "application/set-payment-initiation"}, + {".setreg", "application/set-registration-initiation"}, + {".sgm", "text/x-sgml"}, + {".sgml", "text/x-sgml"}, + {".sh", "application/x-sh"}, + {".shar", "application/x-shar"}, + {".shtml", "magnus-internal/parsed-html"}, + {".shw", "application/presentations"}, + {".si6", "image/si6"}, + {".si7", "image/vnd.stiwap.sis"}, + {".si9", "image/vnd.lgtwap.sis"}, + {".sis", "application/vnd.symbian.install"}, + {".sit", "application/x-stuffit"}, + {".skd", "application/x-Koan"}, + {".skm", "application/x-Koan"}, + {".skp", "application/x-Koan"}, + {".skt", "application/x-Koan"}, + {".slc", "application/x-salsa"}, + {".smd", "audio/x-smd"}, + {".smi", "application/smil"}, + {".smil", "application/smil"}, + {".smp", "application/studiom"}, + {".smz", "audio/x-smd"}, + {".snd", "audio/basic"}, + {".spc", "application/x-pkcs7-certificates"}, + {".spl", "application/futuresplash"}, + {".spr", "application/x-sprite"}, + {".sprite", "application/x-sprite"}, + {".sdp", "application/sdp"}, + {".spt", "application/x-spt"}, + {".src", "application/x-wais-source"}, + {".sst", "application/vnd.ms-pkicertstore"}, + {".stk", "application/hyperstudio"}, + {".stl", "application/vnd.ms-pkistl"}, + {".stm", "text/html"}, + {".svg", "image/svg+xml"}, + {".sv4cpio", "application/x-sv4cpio"}, + {".sv4crc", "application/x-sv4crc"}, + {".svf", "image/vnd"}, + {".eot", "application/vnd.ms-fontobject"}, + {".woff", "application/font-woff"}, + {".svh", "image/svh"}, + {".svr", "x-world/x-svr"}, + {".swf", "application/x-shockwave-flash"}, + {".swfl", "application/x-shockwave-flash"}, + {".t", "application/x-troff"}, + {".tad", "application/octet-stream"}, + {".talk", "text/x-speech"}, + {".tar", "application/x-tar"}, + {".taz", "application/x-tar"}, + {".tbp", "application/x-timbuktu"}, + {".tbt", "application/x-timbuktu"}, + {".tcl", "application/x-tcl"}, + {".tex", "application/x-tex"}, + {".texi", "application/x-texinfo"}, + {".texinfo", "application/x-texinfo"}, + {".tgz", "application/x-compressed"}, + {".thm", "application/vnd.eri.thm"}, + {".tif", "image/tiff"}, + {".tiff", "image/tiff"}, + {".tki", "application/x-tkined"}, + {".tkined", "application/x-tkined"}, + {".toc", "application/toc"}, + {".toy", "image/toy"}, + {".tr", "application/x-troff"}, + {".trk", "x-lml/x-gps"}, + {".trm", "application/x-msterminal"}, + {".tsi", "audio/tsplayer"}, + {".tsp", "application/dsptype"}, + {".tsv", "text/tab-separated-values"}, + {".ttf", "application/octet-stream"}, + {".ttz", "application/t-time"}, + {".txt", "text/plain"}, + {".uls", "text/iuls"}, + {".ult", "audio/x-mod"}, + {".ustar", "application/x-ustar"}, + {".uu", "application/x-uuencode"}, + {".uue", "application/x-uuencode"}, + {".vcd", "application/x-cdlink"}, + {".vcf", "text/x-vcard"}, + {".vdo", "video/vdo"}, + {".vib", "audio/vib"}, + {".viv", "video/vivo"}, + {".vivo", "video/vivo"}, + {".vmd", "application/vocaltec-media-desc"}, + {".vmf", "application/vocaltec-media-file"}, + {".vmi", "application/x-dreamcast-vms-info"}, + {".vms", "application/x-dreamcast-vms"}, + {".vox", "audio/voxware"}, + {".vqe", "audio/x-twinvq-plugin"}, + {".vqf", "audio/x-twinvq"}, + {".vql", "audio/x-twinvq"}, + {".vre", "x-world/x-vream"}, + {".vrml", "x-world/x-vrml"}, + {".vrt", "x-world/x-vrt"}, + {".vrw", "x-world/x-vream"}, + {".vts", "workbook/formulaone"}, + {".wav", "audio/x-wav"}, + {".wax", "audio/x-ms-wax"}, + {".wbmp", "image/vnd.wap.wbmp"}, + {".wcm", "application/vnd.ms-works"}, + {".wdb", "application/vnd.ms-works"}, + {".web", "application/vnd.xara"}, + {".wi", "image/wavelet"}, + {".wis", "application/x-InstallShield"}, + {".wks", "application/vnd.ms-works"}, + {".wm", "video/x-ms-wm"}, + {".wma", "audio/x-ms-wma"}, + {".wmd", "application/x-ms-wmd"}, + {".wmf", "application/x-msmetafile"}, + {".wml", "text/vnd.wap.wml"}, + {".wmlc", "application/vnd.wap.wmlc"}, + {".wmls", "text/vnd.wap.wmlscript"}, + {".wmlsc", "application/vnd.wap.wmlscriptc"}, + {".wmlscript", "text/vnd.wap.wmlscript"}, + {".wmv", "audio/x-ms-wmv"}, + {".wmx", "video/x-ms-wmx"}, + {".wmz", "application/x-ms-wmz"}, + {".wpng", "image/x-up-wpng"}, + {".wps", "application/vnd.ms-works"}, + {".wpt", "x-lml/x-gps"}, + {".wri", "application/x-mswrite"}, + {".wrl", "x-world/x-vrml"}, + {".wrz", "x-world/x-vrml"}, + {".ws", "text/vnd.wap.wmlscript"}, + {".wsc", "application/vnd.wap.wmlscriptc"}, + {".wv", "video/wavelet"}, + {".wvx", "video/x-ms-wvx"}, + {".wxl", "application/x-wxl"}, + {".x-gzip", "application/x-gzip"}, + {".xaf", "x-world/x-vrml"}, + {".xar", "application/vnd.xara"}, + {".xbm", "image/x-xbitmap"}, + {".xdm", "application/x-xdma"}, + {".xdma", "application/x-xdma"}, + {".xdw", "application/vnd.fujixerox.docuworks"}, + {".xht", "application/xhtml+xml"}, + {".xhtm", "application/xhtml+xml"}, + {".xhtml", "application/xhtml+xml"}, + {".xla", "application/vnd.ms-excel"}, + {".xlc", "application/vnd.ms-excel"}, + {".xll", "application/x-excel"}, + {".xlm", "application/vnd.ms-excel"}, + {".xls", "application/vnd.ms-excel"}, + {".xlsx", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {".xlt", "application/vnd.ms-excel"}, + {".xlw", "application/vnd.ms-excel"}, + {".xm", "audio/x-mod"}, + {".xml", "text/plain"}, + {".xml", "application/xml"}, + {".xmz", "audio/x-mod"}, + {".xof", "x-world/x-vrml"}, + {".xpi", "application/x-xpinstall"}, + {".xpm", "image/x-xpixmap"}, + {".xsit", "text/xml"}, + {".xsl", "text/xml"}, + {".xul", "text/xul"}, + {".xwd", "image/x-xwindowdump"}, + {".xyz", "chemical/x-pdb"}, + {".yz1", "application/x-yz1"}, + {".z", "application/x-compress"}, + {".zac", "application/x-zaurus-zac"}, + {".zip", "application/zip"}, + {".json", "application/json"}, + {".7z", "application/x-7z-compressed"}, +}; - static std::map res_mime_map = { - {cinatra::req_content_type::html,"text/html; charset=UTF-8"}, - {cinatra::req_content_type::json,"application/json; charset=UTF-8"}, - {cinatra::req_content_type::string,"text/plain; charset=UTF-8"}, - {cinatra::req_content_type::multipart,"multipart/form-data; boundary="} - }; +static std::map res_mime_map = { + {cinatra::req_content_type::html, "text/html; charset=UTF-8"}, + {cinatra::req_content_type::json, "application/json; charset=UTF-8"}, + {cinatra::req_content_type::string, "text/plain; charset=UTF-8"}, + {cinatra::req_content_type::multipart, "multipart/form-data; boundary="}}; - inline std::string_view get_mime_type(std::string_view extension) { - auto it = mime_map.find(std::string(extension.data(), extension.size())); - if (it == mime_map.end()) { - return "application/octet-stream"; - } +inline std::string_view get_mime_type(std::string_view extension) { + auto it = mime_map.find(std::string(extension.data(), extension.size())); + if (it == mime_map.end()) { + return "application/octet-stream"; + } - return it->second; - } + return it->second; } +} // namespace cinatra diff --git a/include/cinatra/modern_callback.h b/include/cinatra/modern_callback.h index 17faf00..c8b4764 100644 --- a/include/cinatra/modern_callback.h +++ b/include/cinatra/modern_callback.h @@ -14,19 +14,27 @@ *limitations under the License. */ -//Modern Callback +// Modern Callback // -//An asynchronous function that uses callbacks to process results will involve the following concepts: -//_Input_t...: Input parameters of asynchronous functions; -//_Signature_t: The function signature of this asynchronous callback; should meet the type of 'void (_Exception_t, _Result_t ...)' or 'void (_Result_t ...)’ -//_Callable_t: Callback function or mark, if it is a callback function, it needs to comply with the signature type of _Signature_t. This callback must be called once, and only once; -//_Return_t: The return value of the asynchronous function; -//_Result_t...: The result value after the completion of the asynchronous function is used as the input parameter of the callback function; this parameter can have zero or more; -//_Exception_t: The exception of the callback function, if you don't like the exception, ignore this part, but you have to handle the exception properly with the asynchronous code; +// An asynchronous function that uses callbacks to process results will involve +// the following concepts: _Input_t...: Input parameters of asynchronous +//functions; _Signature_t: The function signature of this asynchronous callback; +//should meet the type of 'void (_Exception_t, _Result_t ...)' or 'void +//(_Result_t ...)’ _Callable_t: Callback function or mark, if it is a callback +//function, it needs to comply with the signature type of _Signature_t. This +//callback must be called once, and only once; _Return_t: The return value of +//the asynchronous function; _Result_t...: The result value after the completion +//of the asynchronous function is used as the input parameter of the callback +//function; this parameter can have zero or more; _Exception_t: The exception of +//the callback function, if you don't like the exception, ignore this part, but +//you have to handle the exception properly with the asynchronous code; // -//In the callback adapter model, The '_Input_t.../_Result_t/_Exception_t(Optional)' is an inherent part of the functionality provided by asynchronous functions; -//The '_Callable_t / _Return_t' part is not used directly, but is handled separately by the adapter. -//This gives the adapter an opportunity to expand into future mode, call chain mode, and support coroutines. +// In the callback adapter model, The +// '_Input_t.../_Result_t/_Exception_t(Optional)' is an inherent part of the +// functionality provided by asynchronous functions; The '_Callable_t / +// _Return_t' part is not used directly, but is handled separately by the +// adapter. This gives the adapter an opportunity to expand into future mode, +// call chain mode, and support coroutines. #pragma once #ifndef MODERN_CALLBACK_HEADER_FILE @@ -34,39 +42,42 @@ #include -//Prepare return_void_t and adapter_t for asynchronous functions -namespace modern_callback -{ - //Solve the syntax problem of returning void through an indirect class in order to optimize the return value - struct return_void_t - { - void get() {} - }; +// Prepare return_void_t and adapter_t for asynchronous functions +namespace modern_callback { +// Solve the syntax problem of returning void through an indirect class in order +// to optimize the return value +struct return_void_t { + void get() {} +}; - //Callback adapter template class - //_Callable_t must conform to _Signature_t signature - //This class does not do any effective work except for transferring tokens - //Real work waits for specialized classes to do - template - struct adapter_t - { - using callback_type = _Callable_t; - using return_type = return_void_t; - using result_type = void; +// Callback adapter template class +//_Callable_t must conform to _Signature_t signature +// This class does not do any effective work except for transferring tokens +// Real work waits for specialized classes to do +template struct adapter_t { + using callback_type = _Callable_t; + using return_type = return_void_t; + using result_type = void; - template - static std::tuple traits(_Callable2_t&& token) { - return { std::forward<_Callable2_t>(token), {} }; - } - }; -} + template + static std::tuple traits(_Callable2_t &&token) { + return {std::forward<_Callable2_t>(token), {}}; + } +}; +} // namespace modern_callback -#define MODERN_CALLBACK_TRAITS(_Token_value, _Signature_t) \ - using _Adapter_t__ = modern_callback::adapter_t>, _Signature_t>; \ - auto _Adapter_value__ = _Adapter_t__::traits(std::forward<_Callable_t>(_Token_value)) +#define MODERN_CALLBACK_TRAITS(_Token_value, _Signature_t) \ + using _Adapter_t__ = modern_callback::adapter_t< \ + std::remove_cv_t>, _Signature_t>; \ + auto _Adapter_value__ = \ + _Adapter_t__::traits(std::forward<_Callable_t>(_Token_value)) #define MODERN_CALLBACK_CALL() std::move(std::get<0>(_Adapter_value__)) -#define MODERN_CALLBACK_RETURN() return std::move(std::get<1>(_Adapter_value__)).get() -#define MODERN_CALLBACK_RESULT(_Signature_t) typename modern_callback::adapter_t>, _Signature_t>::result_type +#define MODERN_CALLBACK_RETURN() \ + return std::move(std::get<1>(_Adapter_value__)).get() +#define MODERN_CALLBACK_RESULT(_Signature_t) \ + typename modern_callback::adapter_t< \ + std::remove_cv_t>, \ + _Signature_t>::result_type #if 0 //tostring_async demonstrates that in other threads, the input value of _Input_t is converted to _Result_t of type std :: string. @@ -94,4 +105,4 @@ auto tostring_async(_Input_t&& value, _Callable_t&& token) } #endif -#endif //MODERN_CALLBACK_HEADER_FILE +#endif // MODERN_CALLBACK_HEADER_FILE diff --git a/include/cinatra/multipart_parser.hpp b/include/cinatra/multipart_parser.hpp index 38d6bd0..f8a21e3 100644 --- a/include/cinatra/multipart_parser.hpp +++ b/include/cinatra/multipart_parser.hpp @@ -1,450 +1,421 @@ #ifndef _MULTIPART_PARSER_H_ #define _MULTIPART_PARSER_H_ -#include -#include #include +#include +#include namespace cinatra { - class multipart_parser { - public: - typedef void(*Callback)(const char *buffer, size_t start, size_t end, void *userData); - - public: - Callback onPartBegin; - Callback onHeaderField; - Callback onHeaderValue; - Callback onHeaderEnd; - Callback onHeadersEnd; - Callback onPartData; - Callback onPartEnd; - Callback onEnd; - void *userData; - - multipart_parser() { - lookbehind = nullptr; - resetCallbacks(); - reset(); - } - - multipart_parser(std::string&& boundary) { - lookbehind = nullptr; - resetCallbacks(); - set_boundary(std::move(boundary)); - } - - ~multipart_parser() { - delete[] lookbehind; - } - - void reset() { - delete[] lookbehind; - state = PARSE_ERROR; - boundary.clear(); - boundaryData = boundary.c_str(); - boundarySize = 0; - lookbehind = nullptr; - lookbehindSize = 0; - flags = 0; - index = 0; - headerFieldMark = UNMARKED; - headerValueMark = UNMARKED; - partDataMark = UNMARKED; - errorReason = "Parser uninitialized."; - } - - void set_boundary(std::string&& boundary) { - reset(); - this->boundary = std::move(boundary); - boundaryData = this->boundary.c_str(); - boundarySize = this->boundary.size(); - indexBoundary(); - lookbehind = new char[boundarySize + 8]; - lookbehindSize = boundarySize + 8; - state = START; - errorReason = "No error."; - } - - size_t feed(const char *buffer, size_t len) { - if (state == PARSE_ERROR || len == 0) { - return 0; - } - - State state = this->state; - int flags = this->flags; - size_t prevIndex = this->index; - size_t index = this->index; - size_t boundaryEnd = boundarySize - 1; - size_t i; - char c, cl; - - for (i = 0; i < len; i++) { - c = buffer[i]; - - switch (state) { - case PARSE_ERROR: - return i; - case START: - index = 0; - state = START_BOUNDARY; - case START_BOUNDARY: - if (index == boundarySize - 2) { - if (c != CR) { - setError("Malformed. Expected CR after boundary."); - return i; - } - index++; - break; - } - else if (index - 1 == boundarySize - 2) { - if (c != LF) { - setError("Malformed. Expected LF after boundary CR."); - return i; - } - index = 0; - callback(onPartBegin); - state = HEADER_FIELD_START; - break; - } - if (c != boundary[index + 2]) { - setError("Malformed. Found different boundary data than the given one."); - return i; - } - index++; - break; - case HEADER_FIELD_START: - state = HEADER_FIELD; - headerFieldMark = i; - index = 0; - case HEADER_FIELD: - if (c == CR) { - headerFieldMark = UNMARKED; - state = HEADERS_ALMOST_DONE; - break; - } - - index++; - if (c == HYPHEN) { - break; - } - - if (c == COLON) { - if (index == 1) { - // empty header field - setError("Malformed first header name character."); - return i; - } - dataCallback(onHeaderField, headerFieldMark, buffer, i, len, true); - state = HEADER_VALUE_START; - break; - } - - cl = lower(c); - if (cl < 'a' || cl > 'z') { - setError("Malformed header name."); - return i; - } - break; - case HEADER_VALUE_START: - if (c == SPACE) { - break; - } - - headerValueMark = i; - state = HEADER_VALUE; - case HEADER_VALUE: - if (c == CR) { - dataCallback(onHeaderValue, headerValueMark, buffer, i, len, true, true); - callback(onHeaderEnd); - state = HEADER_VALUE_ALMOST_DONE; - } - break; - case HEADER_VALUE_ALMOST_DONE: - if (c != LF) { - setError("Malformed header value: LF expected after CR"); - return i; - } - - state = HEADER_FIELD_START; - break; - case HEADERS_ALMOST_DONE: - if (c != LF) { - setError("Malformed header ending: LF expected after CR"); - return i; - } - - callback(onHeadersEnd); - state = PART_DATA_START; - break; - case PART_DATA_START: - state = PART_DATA; - partDataMark = i; - case PART_DATA: - processPartData(prevIndex, index, buffer, len, boundaryEnd, i, c, state, flags); - break; - case END: - break; - default: - return i; - } - } - - dataCallback(onHeaderField, headerFieldMark, buffer, i, len, false); - dataCallback(onHeaderValue, headerValueMark, buffer, i, len, false); - dataCallback(onPartData, partDataMark, buffer, i, len, false); - - this->index = index; - this->state = state; - this->flags = flags; - - return len; - } - - bool succeeded() const { - return state == END; - } - - bool has_error() const { - return state == PARSE_ERROR; - } - - bool stopped() const { - return state == PARSE_ERROR || state == END; - } - - const char *get_error_message() const { - return errorReason; - } - - private: - static const char CR = 13; - static const char LF = 10; - static const char SPACE = 32; - static const char HYPHEN = 45; - static const char COLON = 58; - static const size_t UNMARKED = (size_t)-1; - - enum State { - PARSE_ERROR, - START, - START_BOUNDARY, - HEADER_FIELD_START, - HEADER_FIELD, - HEADER_VALUE_START, - HEADER_VALUE, - HEADER_VALUE_ALMOST_DONE, - HEADERS_ALMOST_DONE, - PART_DATA_START, - PART_DATA, - PART_END, - END - }; - - enum Flags { - PART_BOUNDARY = 1, - LAST_BOUNDARY = 2 - }; - - void resetCallbacks() { - onPartBegin = nullptr; - onHeaderField = nullptr; - onHeaderValue = nullptr; - onHeaderEnd = nullptr; - onHeadersEnd = nullptr; - onPartData = nullptr; - onPartEnd = nullptr; - onEnd = nullptr; - userData = nullptr; - } - - void indexBoundary() { - const char *current; - const char *end = boundaryData + boundarySize; - - memset(boundaryIndex, 0, sizeof(boundaryIndex)); - - for (current = boundaryData; current < end; current++) { - boundaryIndex[(unsigned char)*current] = true; - } - } - - void callback(Callback cb, const char *buffer = nullptr, size_t start = UNMARKED, - size_t end = UNMARKED, bool allowEmpty = false) - { - if (start != UNMARKED && start == end && !allowEmpty) { - return; - } - if (cb != nullptr) { - cb(buffer, start, end, userData); - } - } - - void dataCallback(Callback cb, size_t &mark, const char *buffer, size_t i, size_t bufferLen, - bool clear, bool allowEmpty = false) - { - if (mark == UNMARKED) { - return; - } - - if (!clear) { - callback(cb, buffer, mark, bufferLen, allowEmpty); - mark = 0; - } - else { - callback(cb, buffer, mark, i, allowEmpty); - mark = UNMARKED; - } - } - - char lower(char c) const { - return c | 0x20; - } - - inline bool isBoundaryChar(char c) const { - return boundaryIndex[(unsigned char)c]; - } - - bool isHeaderFieldCharacter(char c) const { - return (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == HYPHEN; - } - - void setError(const char *message) { - state = PARSE_ERROR; - errorReason = message; - } - - void processPartData(size_t &prevIndex, size_t &index, const char *buffer, - size_t len, size_t boundaryEnd, size_t &i, char c, State &state, int &flags) - { - prevIndex = index; - - if (index == 0) { - // boyer-moore derived algorithm to safely skip non-boundary data - while (i + boundarySize <= len) { - if (isBoundaryChar(buffer[i + boundaryEnd])) { - break; - } - - i += boundarySize; - } - if (i == len) { - return; - } - c = buffer[i]; - } - - if (index < boundarySize) { - if (boundary[index] == c) { - if (index == 0) { - dataCallback(onPartData, partDataMark, buffer, i, len, true); - } - index++; - } - else { - index = 0; - } - } - else if (index == boundarySize) { - index++; - if (c == CR) { - // CR = part boundary - flags |= PART_BOUNDARY; - } - else if (c == HYPHEN) { - // HYPHEN = end boundary - flags |= LAST_BOUNDARY; - } - else { - index = 0; - } - } - else if (index - 1 == boundarySize) { - if (flags & PART_BOUNDARY) { - index = 0; - if (c == LF) { - // unset the PART_BOUNDARY flag - flags &= ~PART_BOUNDARY; - callback(onPartEnd); - callback(onPartBegin); - state = HEADER_FIELD_START; - return; - } - } - else if (flags & LAST_BOUNDARY) { - if (c == HYPHEN) { - callback(onPartEnd); - callback(onEnd); - state = END; - } - else { - index = 0; - } - } - else { - index = 0; - } - } - else if (index - 2 == boundarySize) { - if (c == CR) { - index++; - } - else { - index = 0; - } - } - else if (index - boundarySize == 3) { - index = 0; - if (c == LF) { - callback(onPartEnd); - callback(onEnd); - state = END; - return; - } - } - - if (index > 0) { - // when matching a possible boundary, keep a lookbehind reference - // in case it turns out to be a false lead - if (index - 1 >= lookbehindSize) { - setError("Parser bug: index overflows lookbehind buffer. " - "Please send bug report with input file attached."); - throw std::out_of_range("index overflows lookbehind buffer"); - } - else if (index - 1 < 0) { - setError("Parser bug: index underflows lookbehind buffer. " - "Please send bug report with input file attached."); - throw std::out_of_range("index underflows lookbehind buffer"); - } - lookbehind[index - 1] = c; - } - else if (prevIndex > 0) { - // if our boundary turned out to be rubbish, the captured lookbehind - // belongs to partData - callback(onPartData, lookbehind, 0, prevIndex); - prevIndex = 0; - partDataMark = i; - - // reconsider the current character even so it interrupted the sequence - // it could be the beginning of a new sequence - i--; - } - } - - std::string boundary; - const char *boundaryData; - size_t boundarySize; - bool boundaryIndex[256]; - char *lookbehind; - size_t lookbehindSize; - State state; - int flags; - size_t index; - size_t headerFieldMark; - size_t headerValueMark; - size_t partDataMark; - const char *errorReason; - }; -} +class multipart_parser { +public: + typedef void (*Callback)(const char *buffer, size_t start, size_t end, + void *userData); + +public: + Callback onPartBegin; + Callback onHeaderField; + Callback onHeaderValue; + Callback onHeaderEnd; + Callback onHeadersEnd; + Callback onPartData; + Callback onPartEnd; + Callback onEnd; + void *userData; + + multipart_parser() { + lookbehind = nullptr; + resetCallbacks(); + reset(); + } + + multipart_parser(std::string &&boundary) { + lookbehind = nullptr; + resetCallbacks(); + set_boundary(std::move(boundary)); + } + + ~multipart_parser() { delete[] lookbehind; } + + void reset() { + delete[] lookbehind; + state = PARSE_ERROR; + boundary.clear(); + boundaryData = boundary.c_str(); + boundarySize = 0; + lookbehind = nullptr; + lookbehindSize = 0; + flags = 0; + index = 0; + headerFieldMark = UNMARKED; + headerValueMark = UNMARKED; + partDataMark = UNMARKED; + errorReason = "Parser uninitialized."; + } + + void set_boundary(std::string &&boundary) { + reset(); + this->boundary = std::move(boundary); + boundaryData = this->boundary.c_str(); + boundarySize = this->boundary.size(); + indexBoundary(); + lookbehind = new char[boundarySize + 8]; + lookbehindSize = boundarySize + 8; + state = START; + errorReason = "No error."; + } + + size_t feed(const char *buffer, size_t len) { + if (state == PARSE_ERROR || len == 0) { + return 0; + } + + State state = this->state; + int flags = this->flags; + size_t prevIndex = this->index; + size_t index = this->index; + size_t boundaryEnd = boundarySize - 1; + size_t i; + char c, cl; + + for (i = 0; i < len; i++) { + c = buffer[i]; + + switch (state) { + case PARSE_ERROR: + return i; + case START: + index = 0; + state = START_BOUNDARY; + case START_BOUNDARY: + if (index == boundarySize - 2) { + if (c != CR) { + setError("Malformed. Expected CR after boundary."); + return i; + } + index++; + break; + } else if (index - 1 == boundarySize - 2) { + if (c != LF) { + setError("Malformed. Expected LF after boundary CR."); + return i; + } + index = 0; + callback(onPartBegin); + state = HEADER_FIELD_START; + break; + } + if (c != boundary[index + 2]) { + setError( + "Malformed. Found different boundary data than the given one."); + return i; + } + index++; + break; + case HEADER_FIELD_START: + state = HEADER_FIELD; + headerFieldMark = i; + index = 0; + case HEADER_FIELD: + if (c == CR) { + headerFieldMark = UNMARKED; + state = HEADERS_ALMOST_DONE; + break; + } + + index++; + if (c == HYPHEN) { + break; + } + + if (c == COLON) { + if (index == 1) { + // empty header field + setError("Malformed first header name character."); + return i; + } + dataCallback(onHeaderField, headerFieldMark, buffer, i, len, true); + state = HEADER_VALUE_START; + break; + } + + cl = lower(c); + if (cl < 'a' || cl > 'z') { + setError("Malformed header name."); + return i; + } + break; + case HEADER_VALUE_START: + if (c == SPACE) { + break; + } + + headerValueMark = i; + state = HEADER_VALUE; + case HEADER_VALUE: + if (c == CR) { + dataCallback(onHeaderValue, headerValueMark, buffer, i, len, true, + true); + callback(onHeaderEnd); + state = HEADER_VALUE_ALMOST_DONE; + } + break; + case HEADER_VALUE_ALMOST_DONE: + if (c != LF) { + setError("Malformed header value: LF expected after CR"); + return i; + } + + state = HEADER_FIELD_START; + break; + case HEADERS_ALMOST_DONE: + if (c != LF) { + setError("Malformed header ending: LF expected after CR"); + return i; + } + + callback(onHeadersEnd); + state = PART_DATA_START; + break; + case PART_DATA_START: + state = PART_DATA; + partDataMark = i; + case PART_DATA: + processPartData(prevIndex, index, buffer, len, boundaryEnd, i, c, state, + flags); + break; + case END: + break; + default: + return i; + } + } + + dataCallback(onHeaderField, headerFieldMark, buffer, i, len, false); + dataCallback(onHeaderValue, headerValueMark, buffer, i, len, false); + dataCallback(onPartData, partDataMark, buffer, i, len, false); + + this->index = index; + this->state = state; + this->flags = flags; + + return len; + } + + bool succeeded() const { return state == END; } + + bool has_error() const { return state == PARSE_ERROR; } + + bool stopped() const { return state == PARSE_ERROR || state == END; } + + const char *get_error_message() const { return errorReason; } + +private: + static const char CR = 13; + static const char LF = 10; + static const char SPACE = 32; + static const char HYPHEN = 45; + static const char COLON = 58; + static const size_t UNMARKED = (size_t)-1; + + enum State { + PARSE_ERROR, + START, + START_BOUNDARY, + HEADER_FIELD_START, + HEADER_FIELD, + HEADER_VALUE_START, + HEADER_VALUE, + HEADER_VALUE_ALMOST_DONE, + HEADERS_ALMOST_DONE, + PART_DATA_START, + PART_DATA, + PART_END, + END + }; + + enum Flags { PART_BOUNDARY = 1, LAST_BOUNDARY = 2 }; + + void resetCallbacks() { + onPartBegin = nullptr; + onHeaderField = nullptr; + onHeaderValue = nullptr; + onHeaderEnd = nullptr; + onHeadersEnd = nullptr; + onPartData = nullptr; + onPartEnd = nullptr; + onEnd = nullptr; + userData = nullptr; + } + + void indexBoundary() { + const char *current; + const char *end = boundaryData + boundarySize; + + memset(boundaryIndex, 0, sizeof(boundaryIndex)); + + for (current = boundaryData; current < end; current++) { + boundaryIndex[(unsigned char)*current] = true; + } + } + + void callback(Callback cb, const char *buffer = nullptr, + size_t start = UNMARKED, size_t end = UNMARKED, + bool allowEmpty = false) { + if (start != UNMARKED && start == end && !allowEmpty) { + return; + } + if (cb != nullptr) { + cb(buffer, start, end, userData); + } + } + + void dataCallback(Callback cb, size_t &mark, const char *buffer, size_t i, + size_t bufferLen, bool clear, bool allowEmpty = false) { + if (mark == UNMARKED) { + return; + } + + if (!clear) { + callback(cb, buffer, mark, bufferLen, allowEmpty); + mark = 0; + } else { + callback(cb, buffer, mark, i, allowEmpty); + mark = UNMARKED; + } + } + + char lower(char c) const { return c | 0x20; } + + inline bool isBoundaryChar(char c) const { + return boundaryIndex[(unsigned char)c]; + } + + bool isHeaderFieldCharacter(char c) const { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == HYPHEN; + } + + void setError(const char *message) { + state = PARSE_ERROR; + errorReason = message; + } + + void processPartData(size_t &prevIndex, size_t &index, const char *buffer, + size_t len, size_t boundaryEnd, size_t &i, char c, + State &state, int &flags) { + prevIndex = index; + + if (index == 0) { + // boyer-moore derived algorithm to safely skip non-boundary data + while (i + boundarySize <= len) { + if (isBoundaryChar(buffer[i + boundaryEnd])) { + break; + } + + i += boundarySize; + } + if (i == len) { + return; + } + c = buffer[i]; + } + + if (index < boundarySize) { + if (boundary[index] == c) { + if (index == 0) { + dataCallback(onPartData, partDataMark, buffer, i, len, true); + } + index++; + } else { + index = 0; + } + } else if (index == boundarySize) { + index++; + if (c == CR) { + // CR = part boundary + flags |= PART_BOUNDARY; + } else if (c == HYPHEN) { + // HYPHEN = end boundary + flags |= LAST_BOUNDARY; + } else { + index = 0; + } + } else if (index - 1 == boundarySize) { + if (flags & PART_BOUNDARY) { + index = 0; + if (c == LF) { + // unset the PART_BOUNDARY flag + flags &= ~PART_BOUNDARY; + callback(onPartEnd); + callback(onPartBegin); + state = HEADER_FIELD_START; + return; + } + } else if (flags & LAST_BOUNDARY) { + if (c == HYPHEN) { + callback(onPartEnd); + callback(onEnd); + state = END; + } else { + index = 0; + } + } else { + index = 0; + } + } else if (index - 2 == boundarySize) { + if (c == CR) { + index++; + } else { + index = 0; + } + } else if (index - boundarySize == 3) { + index = 0; + if (c == LF) { + callback(onPartEnd); + callback(onEnd); + state = END; + return; + } + } + + if (index > 0) { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + if (index - 1 >= lookbehindSize) { + setError("Parser bug: index overflows lookbehind buffer. " + "Please send bug report with input file attached."); + throw std::out_of_range("index overflows lookbehind buffer"); + } else if (index - 1 < 0) { + setError("Parser bug: index underflows lookbehind buffer. " + "Please send bug report with input file attached."); + throw std::out_of_range("index underflows lookbehind buffer"); + } + lookbehind[index - 1] = c; + } else if (prevIndex > 0) { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + callback(onPartData, lookbehind, 0, prevIndex); + prevIndex = 0; + partDataMark = i; + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; + } + } + + std::string boundary; + const char *boundaryData; + size_t boundarySize; + bool boundaryIndex[256]; + char *lookbehind; + size_t lookbehindSize; + State state; + int flags; + size_t index; + size_t headerFieldMark; + size_t headerValueMark; + size_t partDataMark; + const char *errorReason; +}; +} // namespace cinatra #endif /* _MULTIPART_PARSER_H_ */ diff --git a/include/cinatra/multipart_reader.hpp b/include/cinatra/multipart_reader.hpp index eb37899..59f0408 100644 --- a/include/cinatra/multipart_reader.hpp +++ b/include/cinatra/multipart_reader.hpp @@ -1,139 +1,139 @@ #ifndef _MULTIPART_READER_H_ #define _MULTIPART_READER_H_ +#include "multipart_parser.hpp" #include -#include #include -#include "multipart_parser.hpp" +#include -namespace cinatra{ +namespace cinatra { using multipart_headers = std::multimap; class multipart_reader { public: - using PartBeginCallback = std::function; - using PartDataCallback = std::function; - using PartDataEnd = std::function; - //typedef void (*PartBeginCallback)(const multipart_headers &headers); - //typedef void (*PartDataCallback)(const char *buffer, size_t size); - //typedef void (*Callback)(); - - PartBeginCallback on_part_begin; - PartDataCallback on_part_data; - PartDataEnd on_part_end; - PartDataEnd on_end; - - multipart_reader() { - resetReaderCallbacks(); - setParserCallbacks(); - } - - void reset() { - parser.reset(); - } - - void set_boundary(std::string&& boundary) { - parser.set_boundary(std::move(boundary)); //should add \r\n-- ? - } - - size_t feed(const char *buffer, size_t len) { - return parser.feed(buffer, len); - } - - bool succeeded() const { - return parser.succeeded(); - } - - bool has_error() const { - return parser.has_error(); - } - - bool stopped() const { - return parser.stopped(); - } - - const char *get_error_message() const { - return parser.get_error_message(); - } + using PartBeginCallback = std::function; + using PartDataCallback = std::function; + using PartDataEnd = std::function; + // typedef void (*PartBeginCallback)(const multipart_headers &headers); + // typedef void (*PartDataCallback)(const char *buffer, size_t size); + // typedef void (*Callback)(); + + PartBeginCallback on_part_begin; + PartDataCallback on_part_data; + PartDataEnd on_part_end; + PartDataEnd on_end; + + multipart_reader() { + resetReaderCallbacks(); + setParserCallbacks(); + } + + void reset() { parser.reset(); } + + void set_boundary(std::string &&boundary) { + parser.set_boundary(std::move(boundary)); // should add \r\n-- ? + } + + size_t feed(const char *buffer, size_t len) { + return parser.feed(buffer, len); + } + + bool succeeded() const { return parser.succeeded(); } + + bool has_error() const { return parser.has_error(); } + + bool stopped() const { return parser.stopped(); } + + const char *get_error_message() const { return parser.get_error_message(); } private: - void resetReaderCallbacks() { - on_part_begin = nullptr; - on_part_data = nullptr; - on_part_end = nullptr; - on_end = nullptr; - } - - void setParserCallbacks() { - parser.onPartBegin = cbPartBegin; - parser.onHeaderField = cbHeaderField; - parser.onHeaderValue = cbHeaderValue; - parser.onHeaderEnd = cbHeaderEnd; - parser.onHeadersEnd = cbHeadersEnd; - parser.onPartData = cbPartData; - parser.onPartEnd = cbPartEnd; - parser.onEnd = cbEnd; - parser.userData = this; - } - - static void cbPartBegin(const char *buffer, size_t start, size_t end, void *userData) { - //multipart_reader *self = (multipart_reader *)userData; - //self->currentHeaders.clear(); - } - - static void cbHeaderField(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - self->currentHeaderName += { buffer + start, end - start }; - } - - static void cbHeaderValue(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - self->currentHeaderValue += { buffer + start, end - start }; - } - - static void cbHeaderEnd(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - self->currentHeaders.emplace(self->currentHeaderName, self->currentHeaderValue); - self->currentHeaderName.clear(); - self->currentHeaderValue.clear(); - //self->currentHeaders.emplace(std::string{ self->currentHeaderName.data(), self->currentHeaderName.length() }, - // std::string{ self->currentHeaderValue.data(), self->currentHeaderValue.length() }); - } - - static void cbHeadersEnd(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - if (self->on_part_begin != nullptr) { - self->on_part_begin(self->currentHeaders); - } - self->currentHeaders.clear(); - } - - static void cbPartData(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - if (self->on_part_data != nullptr) { - self->on_part_data(buffer + start, end - start); - } - } - - static void cbPartEnd(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - if (self->on_part_end != nullptr) { - self->on_part_end(); - } - } - - static void cbEnd(const char *buffer, size_t start, size_t end, void *userData) { - multipart_reader *self = (multipart_reader *)userData; - if (self->on_end != nullptr) { - self->on_end(); - } - } + void resetReaderCallbacks() { + on_part_begin = nullptr; + on_part_data = nullptr; + on_part_end = nullptr; + on_end = nullptr; + } + + void setParserCallbacks() { + parser.onPartBegin = cbPartBegin; + parser.onHeaderField = cbHeaderField; + parser.onHeaderValue = cbHeaderValue; + parser.onHeaderEnd = cbHeaderEnd; + parser.onHeadersEnd = cbHeadersEnd; + parser.onPartData = cbPartData; + parser.onPartEnd = cbPartEnd; + parser.onEnd = cbEnd; + parser.userData = this; + } + + static void cbPartBegin(const char *buffer, size_t start, size_t end, + void *userData) { + // multipart_reader *self = (multipart_reader *)userData; + // self->currentHeaders.clear(); + } + + static void cbHeaderField(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + self->currentHeaderName += {buffer + start, end - start}; + } + + static void cbHeaderValue(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + self->currentHeaderValue += {buffer + start, end - start}; + } + + static void cbHeaderEnd(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + self->currentHeaders.emplace(self->currentHeaderName, + self->currentHeaderValue); + self->currentHeaderName.clear(); + self->currentHeaderValue.clear(); + // self->currentHeaders.emplace(std::string{ self->currentHeaderName.data(), + // self->currentHeaderName.length() }, std::string{ + //self->currentHeaderValue.data(), self->currentHeaderValue.length() }); + } + + static void cbHeadersEnd(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + if (self->on_part_begin != nullptr) { + self->on_part_begin(self->currentHeaders); + } + self->currentHeaders.clear(); + } + + static void cbPartData(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + if (self->on_part_data != nullptr) { + self->on_part_data(buffer + start, end - start); + } + } + + static void cbPartEnd(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + if (self->on_part_end != nullptr) { + self->on_part_end(); + } + } + + static void cbEnd(const char *buffer, size_t start, size_t end, + void *userData) { + multipart_reader *self = (multipart_reader *)userData; + if (self->on_end != nullptr) { + self->on_end(); + } + } private: - multipart_parser parser; - multipart_headers currentHeaders; - std::string currentHeaderName, currentHeaderValue; - void *userData; + multipart_parser parser; + multipart_headers currentHeaders; + std::string currentHeaderName, currentHeaderValue; + void *userData; }; -} +} // namespace cinatra #endif /* _MULTIPART_READER_H_ */ diff --git a/include/cinatra/nlohmann_json.hpp b/include/cinatra/nlohmann_json.hpp index 06da815..98febf9 100644 --- a/include/cinatra/nlohmann_json.hpp +++ b/include/cinatra/nlohmann_json.hpp @@ -34,72 +34,62 @@ SOFTWARE. #define NLOHMANN_JSON_VERSION_MINOR 7 #define NLOHMANN_JSON_VERSION_PATCH 3 -#include // all_of, find, for_each -#include // assert -#include // and, not, or -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less #include // initializer_list -#include // istream, ostream -#include // random_access_iterator_tag -#include // unique_ptr -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap -#include // vector +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector // #include - #include // #include - -#include // transform -#include // array -#include // and, not +#include // transform +#include // array +#include // and, not #include // forward_list -#include // inserter, front_inserter, end -#include // map -#include // string -#include // tuple, make_tuple +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible #include // unordered_map -#include // pair, declval -#include // valarray +#include // pair, declval +#include // valarray // #include - #include // exception #include // runtime_error -#include // to_string +#include // to_string // #include - #include // size_t -namespace nlohmann -{ -namespace detail -{ +namespace nlohmann { +namespace detail { /// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; - - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const - { - return chars_read_total; - } +struct position_t { + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const { return chars_read_total; } }; } // namespace detail @@ -107,7 +97,6 @@ struct position_t // #include - #include // pair // #include /* Hedley - https://nemequ.github.io/hedley @@ -124,1657 +113,1814 @@ struct position_t #if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) #if defined(JSON_HEDLEY_VERSION) - #undef JSON_HEDLEY_VERSION +#undef JSON_HEDLEY_VERSION #endif #define JSON_HEDLEY_VERSION 11 #if defined(JSON_HEDLEY_STRINGIFY_EX) - #undef JSON_HEDLEY_STRINGIFY_EX +#undef JSON_HEDLEY_STRINGIFY_EX #endif #define JSON_HEDLEY_STRINGIFY_EX(x) #x #if defined(JSON_HEDLEY_STRINGIFY) - #undef JSON_HEDLEY_STRINGIFY +#undef JSON_HEDLEY_STRINGIFY #endif #define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) #if defined(JSON_HEDLEY_CONCAT_EX) - #undef JSON_HEDLEY_CONCAT_EX +#undef JSON_HEDLEY_CONCAT_EX #endif -#define JSON_HEDLEY_CONCAT_EX(a,b) a##b +#define JSON_HEDLEY_CONCAT_EX(a, b) a##b #if defined(JSON_HEDLEY_CONCAT) - #undef JSON_HEDLEY_CONCAT +#undef JSON_HEDLEY_CONCAT #endif -#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) +#define JSON_HEDLEY_CONCAT(a, b) JSON_HEDLEY_CONCAT_EX(a, b) #if defined(JSON_HEDLEY_VERSION_ENCODE) - #undef JSON_HEDLEY_VERSION_ENCODE +#undef JSON_HEDLEY_VERSION_ENCODE #endif -#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) +#define JSON_HEDLEY_VERSION_ENCODE(major, minor, revision) \ + (((major)*1000000) + ((minor)*1000) + (revision)) #if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) - #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#undef JSON_HEDLEY_VERSION_DECODE_MAJOR #endif #define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) #if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) - #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#undef JSON_HEDLEY_VERSION_DECODE_MINOR #endif #define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) #if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) - #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#undef JSON_HEDLEY_VERSION_DECODE_REVISION #endif #define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) #if defined(JSON_HEDLEY_GNUC_VERSION) - #undef JSON_HEDLEY_GNUC_VERSION +#undef JSON_HEDLEY_GNUC_VERSION #endif #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#define JSON_HEDLEY_GNUC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #elif defined(__GNUC__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#define JSON_HEDLEY_GNUC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) #endif #if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) - #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#undef JSON_HEDLEY_GNUC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_GNUC_VERSION) - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION) - #undef JSON_HEDLEY_MSVC_VERSION +#undef JSON_HEDLEY_MSVC_VERSION #endif #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#define JSON_HEDLEY_MSVC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, \ + (_MSC_FULL_VER % 10000000) / 100000, \ + (_MSC_FULL_VER % 100000) / 100) #elif defined(_MSC_FULL_VER) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#define JSON_HEDLEY_MSVC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, \ + (_MSC_FULL_VER % 1000000) / 10000, \ + (_MSC_FULL_VER % 10000) / 10) #elif defined(_MSC_VER) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#define JSON_HEDLEY_MSVC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) #endif #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) - #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#undef JSON_HEDLEY_MSVC_VERSION_CHECK #endif #if !defined(_MSC_VER) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) (0) #elif defined(_MSC_VER) && (_MSC_VER >= 1400) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) #elif defined(_MSC_VER) && (_MSC_VER >= 1200) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) #else - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#define JSON_HEDLEY_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_VER >= ((major * 100) + (minor))) #endif #if defined(JSON_HEDLEY_INTEL_VERSION) - #undef JSON_HEDLEY_INTEL_VERSION +#undef JSON_HEDLEY_INTEL_VERSION #endif #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#define JSON_HEDLEY_INTEL_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, \ + __INTEL_COMPILER_UPDATE) #elif defined(__INTEL_COMPILER) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#define JSON_HEDLEY_INTEL_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif #if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#undef JSON_HEDLEY_INTEL_VERSION_CHECK #endif #if defined(JSON_HEDLEY_INTEL_VERSION) - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_INTEL_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_PGI_VERSION) - #undef JSON_HEDLEY_PGI_VERSION +#undef JSON_HEDLEY_PGI_VERSION #endif -#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) - #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && \ + defined(__PGIC_PATCHLEVEL__) +#define JSON_HEDLEY_PGI_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) #endif #if defined(JSON_HEDLEY_PGI_VERSION_CHECK) - #undef JSON_HEDLEY_PGI_VERSION_CHECK +#undef JSON_HEDLEY_PGI_VERSION_CHECK #endif #if defined(JSON_HEDLEY_PGI_VERSION) - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_PGI_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_PGI_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION) - #undef JSON_HEDLEY_SUNPRO_VERSION +#undef JSON_HEDLEY_SUNPRO_VERSION #endif #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE( \ + (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ + (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \ + (__SUNPRO_C & 0xf) * 10) #elif defined(__SUNPRO_C) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, \ + (__SUNPRO_C)&0xf) #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE( \ + (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ + (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \ + (__SUNPRO_CC & 0xf) * 10) #elif defined(__SUNPRO_CC) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#define JSON_HEDLEY_SUNPRO_VERSION \ + JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, \ + (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC)&0xf) #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) - #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK #endif #if defined(JSON_HEDLEY_SUNPRO_VERSION) - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_SUNPRO_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION #endif #if defined(__EMSCRIPTEN__) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#define JSON_HEDLEY_EMSCRIPTEN_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, \ + __EMSCRIPTEN_tiny__) #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK #endif #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_EMSCRIPTEN_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_ARM_VERSION) - #undef JSON_HEDLEY_ARM_VERSION +#undef JSON_HEDLEY_ARM_VERSION #endif #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#define JSON_HEDLEY_ARM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, \ + (__ARMCOMPILER_VERSION % 1000000) / 10000, \ + (__ARMCOMPILER_VERSION % 10000) / 100) #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#define JSON_HEDLEY_ARM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, \ + (__ARMCC_VERSION % 1000000) / 10000, \ + (__ARMCC_VERSION % 10000) / 100) #endif #if defined(JSON_HEDLEY_ARM_VERSION_CHECK) - #undef JSON_HEDLEY_ARM_VERSION_CHECK +#undef JSON_HEDLEY_ARM_VERSION_CHECK #endif #if defined(JSON_HEDLEY_ARM_VERSION) - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_ARM_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_ARM_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_IBM_VERSION) - #undef JSON_HEDLEY_IBM_VERSION +#undef JSON_HEDLEY_IBM_VERSION #endif #if defined(__ibmxl__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#define JSON_HEDLEY_IBM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, \ + __ibmxl_modification__) #elif defined(__xlC__) && defined(__xlC_ver__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#define JSON_HEDLEY_IBM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, \ + (__xlC_ver__ >> 8) & 0xff) #elif defined(__xlC__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#define JSON_HEDLEY_IBM_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) #endif #if defined(JSON_HEDLEY_IBM_VERSION_CHECK) - #undef JSON_HEDLEY_IBM_VERSION_CHECK +#undef JSON_HEDLEY_IBM_VERSION_CHECK #endif #if defined(JSON_HEDLEY_IBM_VERSION) - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_IBM_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_IBM_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_TI_VERSION) - #undef JSON_HEDLEY_TI_VERSION +#undef JSON_HEDLEY_TI_VERSION #endif #if defined(__TI_COMPILER_VERSION__) - #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#define JSON_HEDLEY_TI_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) #endif #if defined(JSON_HEDLEY_TI_VERSION_CHECK) - #undef JSON_HEDLEY_TI_VERSION_CHECK +#undef JSON_HEDLEY_TI_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TI_VERSION) - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_TI_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_TI_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_CRAY_VERSION) - #undef JSON_HEDLEY_CRAY_VERSION +#undef JSON_HEDLEY_CRAY_VERSION #endif #if defined(_CRAYC) - #if defined(_RELEASE_PATCHLEVEL) - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) - #else - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) - #endif +#if defined(_RELEASE_PATCHLEVEL) +#define JSON_HEDLEY_CRAY_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, \ + _RELEASE_PATCHLEVEL) +#else +#define JSON_HEDLEY_CRAY_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) +#endif #endif #if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) - #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#undef JSON_HEDLEY_CRAY_VERSION_CHECK #endif #if defined(JSON_HEDLEY_CRAY_VERSION) - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_CRAY_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_IAR_VERSION) - #undef JSON_HEDLEY_IAR_VERSION +#undef JSON_HEDLEY_IAR_VERSION #endif #if defined(__IAR_SYSTEMS_ICC__) - #if __VER__ > 1000 - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) - #else - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) - #endif +#if __VER__ > 1000 +#define JSON_HEDLEY_IAR_VERSION \ + JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), \ + (__VER__ % 1000)) +#else +#define JSON_HEDLEY_IAR_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) +#endif #endif #if defined(JSON_HEDLEY_IAR_VERSION_CHECK) - #undef JSON_HEDLEY_IAR_VERSION_CHECK +#undef JSON_HEDLEY_IAR_VERSION_CHECK #endif #if defined(JSON_HEDLEY_IAR_VERSION) - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_IAR_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_IAR_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_TINYC_VERSION) - #undef JSON_HEDLEY_TINYC_VERSION +#undef JSON_HEDLEY_TINYC_VERSION #endif #if defined(__TINYC__) - #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#define JSON_HEDLEY_TINYC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, \ + __TINYC__ % 100) #endif #if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) - #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#undef JSON_HEDLEY_TINYC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_TINYC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_DMC_VERSION) - #undef JSON_HEDLEY_DMC_VERSION +#undef JSON_HEDLEY_DMC_VERSION #endif #if defined(__DMC__) - #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#define JSON_HEDLEY_DMC_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) #endif #if defined(JSON_HEDLEY_DMC_VERSION_CHECK) - #undef JSON_HEDLEY_DMC_VERSION_CHECK +#undef JSON_HEDLEY_DMC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_DMC_VERSION) - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_DMC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_DMC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION) - #undef JSON_HEDLEY_COMPCERT_VERSION +#undef JSON_HEDLEY_COMPCERT_VERSION #endif #if defined(__COMPCERT_VERSION__) - #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#define JSON_HEDLEY_COMPCERT_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, \ + (__COMPCERT_VERSION__ / 100) % 100, \ + __COMPCERT_VERSION__ % 100) #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) - #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK #endif #if defined(JSON_HEDLEY_COMPCERT_VERSION) - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_COMPCERT_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_PELLES_VERSION) - #undef JSON_HEDLEY_PELLES_VERSION +#undef JSON_HEDLEY_PELLES_VERSION #endif #if defined(__POCC__) - #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#define JSON_HEDLEY_PELLES_VERSION \ + JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) #endif #if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) - #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#undef JSON_HEDLEY_PELLES_VERSION_CHECK #endif #if defined(JSON_HEDLEY_PELLES_VERSION) - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_PELLES_VERSION >= \ + JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_PELLES_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_GCC_VERSION) - #undef JSON_HEDLEY_GCC_VERSION +#undef JSON_HEDLEY_GCC_VERSION #endif -#if \ - defined(JSON_HEDLEY_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(JSON_HEDLEY_INTEL_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_ARM_VERSION) && \ - !defined(JSON_HEDLEY_TI_VERSION) && \ - !defined(__COMPCERT__) - #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#if defined(JSON_HEDLEY_GNUC_VERSION) && !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && !defined(__COMPCERT__) +#define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION #endif #if defined(JSON_HEDLEY_GCC_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_VERSION_CHECK +#undef JSON_HEDLEY_GCC_VERSION_CHECK #endif #if defined(JSON_HEDLEY_GCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#define JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) \ + (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) #else - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) (0) #endif #if defined(JSON_HEDLEY_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_ATTRIBUTE +#undef JSON_HEDLEY_HAS_ATTRIBUTE #endif #if defined(__has_attribute) - #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) #else - #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + __has_attribute(attribute) #else - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE #endif #if defined(__has_attribute) - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + __has_attribute(attribute) #else - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE #endif -#if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#if defined(__has_cpp_attribute) && defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) #else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS #endif #if !defined(__cplusplus) || !defined(__has_cpp_attribute) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#elif \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) (0) +#elif !defined(JSON_HEDLEY_PGI_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(19, 20, 0)) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) \ + JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) #else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns, attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + __has_cpp_attribute(attribute) #else - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE #endif #if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + __has_cpp_attribute(attribute) #else - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_HAS_BUILTIN) - #undef JSON_HEDLEY_HAS_BUILTIN +#undef JSON_HEDLEY_HAS_BUILTIN #endif #if defined(__has_builtin) - #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) #else - #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) - #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#undef JSON_HEDLEY_GNUC_HAS_BUILTIN #endif #if defined(__has_builtin) - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ + __has_builtin(builtin) #else - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) - #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#undef JSON_HEDLEY_GCC_HAS_BUILTIN #endif #if defined(__has_builtin) - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) \ + __has_builtin(builtin) #else - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_HAS_FEATURE) - #undef JSON_HEDLEY_HAS_FEATURE +#undef JSON_HEDLEY_HAS_FEATURE #endif #if defined(__has_feature) - #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) #else - #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#define JSON_HEDLEY_HAS_FEATURE(feature) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) - #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#undef JSON_HEDLEY_GNUC_HAS_FEATURE #endif #if defined(__has_feature) - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#define JSON_HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) \ + __has_feature(feature) #else - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_FEATURE(feature, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_FEATURE) - #undef JSON_HEDLEY_GCC_HAS_FEATURE +#undef JSON_HEDLEY_GCC_HAS_FEATURE #endif #if defined(__has_feature) - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#define JSON_HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) \ + __has_feature(feature) #else - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_FEATURE(feature, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_HAS_EXTENSION) - #undef JSON_HEDLEY_HAS_EXTENSION +#undef JSON_HEDLEY_HAS_EXTENSION #endif #if defined(__has_extension) - #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) #else - #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#define JSON_HEDLEY_HAS_EXTENSION(extension) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) - #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#undef JSON_HEDLEY_GNUC_HAS_EXTENSION #endif #if defined(__has_extension) - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) \ + __has_extension(extension) #else - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) - #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#undef JSON_HEDLEY_GCC_HAS_EXTENSION #endif #if defined(__has_extension) - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#define JSON_HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) \ + __has_extension(extension) #else - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_EXTENSION(extension, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) \ + __has_declspec_attribute(attribute) #else - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, \ + patch) \ + __has_declspec_attribute(attribute) #else - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, \ + patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE #endif #if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) \ + __has_declspec_attribute(attribute) #else - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_HAS_WARNING) - #undef JSON_HEDLEY_HAS_WARNING +#undef JSON_HEDLEY_HAS_WARNING #endif #if defined(__has_warning) - #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) #else - #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#define JSON_HEDLEY_HAS_WARNING(warning) (0) #endif #if defined(JSON_HEDLEY_GNUC_HAS_WARNING) - #undef JSON_HEDLEY_GNUC_HAS_WARNING +#undef JSON_HEDLEY_GNUC_HAS_WARNING #endif #if defined(__has_warning) - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#define JSON_HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) \ + __has_warning(warning) #else - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GNUC_HAS_WARNING(warning, major, minor, patch) \ + JSON_HEDLEY_GNUC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_GCC_HAS_WARNING) - #undef JSON_HEDLEY_GCC_HAS_WARNING +#undef JSON_HEDLEY_GCC_HAS_WARNING #endif #if defined(__has_warning) - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#define JSON_HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) \ + __has_warning(warning) #else - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_HAS_WARNING(warning, major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif /* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ #endif #if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr JSON_HEDLEY_DIAGNOSTIC_POP #else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x -#endif - -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) - #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18, 4, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6, 0, 0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) && \ + defined(__C99_PRAGMA_OPERATOR)) +#define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_PRAGMA(value) __pragma(value) #else - #define JSON_HEDLEY_PRAGMA(value) +#define JSON_HEDLEY_PRAGMA(value) #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) - #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#undef JSON_HEDLEY_DIAGNOSTIC_PUSH #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_POP) - #undef JSON_HEDLEY_DIAGNOSTIC_POP +#undef JSON_HEDLEY_DIAGNOSTIC_POP #endif #if defined(__clang__) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) - #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) +#define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5, 6, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8, 1, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") +#define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") #else - #define JSON_HEDLEY_DIAGNOSTIC_PUSH - #define JSON_HEDLEY_DIAGNOSTIC_POP +#define JSON_HEDLEY_DIAGNOSTIC_PUSH +#define JSON_HEDLEY_DIAGNOSTIC_POP #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + __pragma(warning(disable : 4996)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && !defined(__cplusplus) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) && defined(__cplusplus) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED \ + _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 90, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") #else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + __pragma(warning(disable : 4068)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + _Pragma("diag_suppress=Pe161") #else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") -#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + __pragma(warning(disable : 5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("error_messages(off,attrskipunsup)") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES \ + _Pragma("diag_suppress 1173") #else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES #endif #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") #else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL #endif #if defined(JSON_HEDLEY_DEPRECATED) - #undef JSON_HEDLEY_DEPRECATED +#undef JSON_HEDLEY_DEPRECATED #endif #if defined(JSON_HEDLEY_DEPRECATED_FOR) - #undef JSON_HEDLEY_DEPRECATED_FOR +#undef JSON_HEDLEY_DEPRECATED_FOR #endif #if defined(__cplusplus) && (__cplusplus >= 201402L) - #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) -#elif \ - JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#define JSON_HEDLEY_DEPRECATED(since) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_( \ + [[deprecated("Since " #since)]]) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_( \ + [[deprecated("Since " #since "; use " #replacement)]]) +#elif JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 13, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 3, 0) +#define JSON_HEDLEY_DEPRECATED(since) \ + __attribute__((__deprecated__("Since " #since))) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + __attribute__((__deprecated__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) +#define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " #since)) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) \ + __declspec(deprecated("Since " #since "; use " #replacement)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6, 50, 0) +#define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") #else - #define JSON_HEDLEY_DEPRECATED(since) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#define JSON_HEDLEY_DEPRECATED(since) +#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) #endif #if defined(JSON_HEDLEY_UNAVAILABLE) - #undef JSON_HEDLEY_UNAVAILABLE +#undef JSON_HEDLEY_UNAVAILABLE #endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#if JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 3, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_UNAVAILABLE(available_since) \ + __attribute__((__warning__("Not available until " #available_since))) #else - #define JSON_HEDLEY_UNAVAILABLE(available_since) +#define JSON_HEDLEY_UNAVAILABLE(available_since) #endif #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#undef JSON_HEDLEY_WARN_UNUSED_RESULT #endif #if defined(__cplusplus) && (__cplusplus >= 201703L) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#define JSON_HEDLEY_WARN_UNUSED_RESULT \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ - #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ #else - #define JSON_HEDLEY_WARN_UNUSED_RESULT +#define JSON_HEDLEY_WARN_UNUSED_RESULT #endif #if defined(JSON_HEDLEY_SENTINEL) - #undef JSON_HEDLEY_SENTINEL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) - #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#undef JSON_HEDLEY_SENTINEL +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 4, 0) +#define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) #else - #define JSON_HEDLEY_SENTINEL(position) +#define JSON_HEDLEY_SENTINEL(position) #endif #if defined(JSON_HEDLEY_NO_RETURN) - #undef JSON_HEDLEY_NO_RETURN +#undef JSON_HEDLEY_NO_RETURN #endif -#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NO_RETURN __noreturn -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#if JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define JSON_HEDLEY_NO_RETURN _Noreturn +#define JSON_HEDLEY_NO_RETURN _Noreturn #elif defined(__cplusplus) && (__cplusplus >= 201103L) - #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#define JSON_HEDLEY_NO_RETURN \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 2, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(17, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) +#define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define JSON_HEDLEY_NO_RETURN __declspec(noreturn) #else - #define JSON_HEDLEY_NO_RETURN +#define JSON_HEDLEY_NO_RETURN #endif #if defined(JSON_HEDLEY_NO_ESCAPE) - #undef JSON_HEDLEY_NO_ESCAPE +#undef JSON_HEDLEY_NO_ESCAPE #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) - #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) #else - #define JSON_HEDLEY_NO_ESCAPE +#define JSON_HEDLEY_NO_ESCAPE #endif #if defined(JSON_HEDLEY_UNREACHABLE) - #undef JSON_HEDLEY_UNREACHABLE +#undef JSON_HEDLEY_UNREACHABLE #endif #if defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #undef JSON_HEDLEY_UNREACHABLE_RETURN -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) - #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) - #define JSON_HEDLEY_UNREACHABLE() __assume(0) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) - #else - #define JSON_HEDLEY_UNREACHABLE() _nassert(0) - #endif - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && \ + (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 5) +#define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) +#define JSON_HEDLEY_UNREACHABLE() __assume(0) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6, 0, 0) +#if defined(__cplusplus) +#define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) +#else +#define JSON_HEDLEY_UNREACHABLE() _nassert(0) +#endif +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value #elif defined(EXIT_FAILURE) - #define JSON_HEDLEY_UNREACHABLE() abort() +#define JSON_HEDLEY_UNREACHABLE() abort() #else - #define JSON_HEDLEY_UNREACHABLE() - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#define JSON_HEDLEY_UNREACHABLE() +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value #endif #if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() +#define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() #endif #if defined(JSON_HEDLEY_ASSUME) - #undef JSON_HEDLEY_ASSUME +#undef JSON_HEDLEY_ASSUME #endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#if JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_ASSUME(expr) __assume(expr) #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) - #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) - #else - #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) - #endif -#elif \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) - #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) +#define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6, 0, 0) +#if defined(__cplusplus) +#define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) #else - #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) +#define JSON_HEDLEY_ASSUME(expr) _nassert(expr) +#endif +#elif (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && \ + !defined(JSON_HEDLEY_ARM_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 5, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 5) +#define JSON_HEDLEY_ASSUME(expr) \ + ((void)((expr) ? 1 : (__builtin_unreachable(), 1))) +#else +#define JSON_HEDLEY_ASSUME(expr) ((void)(expr)) #endif JSON_HEDLEY_DIAGNOSTIC_PUSH #if JSON_HEDLEY_HAS_WARNING("-Wpedantic") - #pragma clang diagnostic ignored "-Wpedantic" +#pragma clang diagnostic ignored "-Wpedantic" #endif #if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) - #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros", 4, 0, 0) +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wvariadic-macros" +#elif defined(JSON_HEDLEY_GCC_VERSION) +#pragma GCC diagnostic ignored "-Wvariadic-macros" #endif -#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) - #if defined(__clang__) - #pragma clang diagnostic ignored "-Wvariadic-macros" - #elif defined(JSON_HEDLEY_GCC_VERSION) - #pragma GCC diagnostic ignored "-Wvariadic-macros" - #endif #endif #if defined(JSON_HEDLEY_NON_NULL) - #undef JSON_HEDLEY_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#undef JSON_HEDLEY_NON_NULL +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) #else - #define JSON_HEDLEY_NON_NULL(...) +#define JSON_HEDLEY_NON_NULL(...) #endif JSON_HEDLEY_DIAGNOSTIC_POP #if defined(JSON_HEDLEY_PRINTF_FORMAT) - #undef JSON_HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && \ + !defined(__USE_MINGW_ANSI_STDIO) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && \ + JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format, 4, 4, 0) && \ + defined(__USE_MINGW_ANSI_STDIO) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 6, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6, 0, 0) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) \ + __declspec(vaformat(printf, string_idx, first_to_check)) #else - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#define JSON_HEDLEY_PRINTF_FORMAT(string_idx, first_to_check) #endif #if defined(JSON_HEDLEY_CONSTEXPR) - #undef JSON_HEDLEY_CONSTEXPR +#undef JSON_HEDLEY_CONSTEXPR #endif #if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) - #endif +#if __cplusplus >= 201103L +#define JSON_HEDLEY_CONSTEXPR \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) +#endif #endif #if !defined(JSON_HEDLEY_CONSTEXPR) - #define JSON_HEDLEY_CONSTEXPR +#define JSON_HEDLEY_CONSTEXPR #endif #if defined(JSON_HEDLEY_PREDICT) - #undef JSON_HEDLEY_PREDICT +#undef JSON_HEDLEY_PREDICT #endif #if defined(JSON_HEDLEY_LIKELY) - #undef JSON_HEDLEY_LIKELY +#undef JSON_HEDLEY_LIKELY #endif #if defined(JSON_HEDLEY_UNLIKELY) - #undef JSON_HEDLEY_UNLIKELY +#undef JSON_HEDLEY_UNLIKELY #endif #if defined(JSON_HEDLEY_UNPREDICTABLE) - #undef JSON_HEDLEY_UNPREDICTABLE +#undef JSON_HEDLEY_UNPREDICTABLE #endif #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) - #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) -#endif -#if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) -# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9, 0, 0) +#define JSON_HEDLEY_PREDICT(expr, value, probability) \ + __builtin_expect_with_probability(expr, value, probability) +#define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + __builtin_expect_with_probability(!!(expr), 1, probability) +#define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + __builtin_expect_with_probability(!!(expr), 0, probability) +#define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) - #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) -#endif -#elif \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) -# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) \ + __builtin_expect_with_probability(!!(expr), 1, 0.5) +#endif +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 15, 0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6, 1, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 27) +#define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) \ + : (((void)(expected)), !!(expr))) +#define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) \ + ? __builtin_expect(!!(expr), 1) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) \ + : !!(expr))); \ + })) +#define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) \ + ? __builtin_expect(!!(expr), 0) \ + : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) \ + : !!(expr))); \ + })) +#define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +#define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #else -# define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) -# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((void)(expected)), !!(expr)) +#define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +#define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +#define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +#define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) #endif #if !defined(JSON_HEDLEY_UNPREDICTABLE) - #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) #endif #if defined(JSON_HEDLEY_MALLOC) - #undef JSON_HEDLEY_MALLOC -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#undef JSON_HEDLEY_MALLOC +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") #elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) - #define JSON_HEDLEY_MALLOC __declspec(restrict) +#define JSON_HEDLEY_MALLOC __declspec(restrict) #else - #define JSON_HEDLEY_MALLOC +#define JSON_HEDLEY_MALLOC #endif #if defined(JSON_HEDLEY_PURE) - #undef JSON_HEDLEY_PURE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_PURE __attribute__((__pure__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#undef JSON_HEDLEY_PURE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2, 96, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") #else - #define JSON_HEDLEY_PURE +#define JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_CONST) - #undef JSON_HEDLEY_CONST -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_CONST __attribute__((__const__)) -#elif \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#undef JSON_HEDLEY_CONST +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2, 5, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) +#define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) +#define JSON_HEDLEY_CONST _Pragma("no_side_effect") #else - #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#define JSON_HEDLEY_CONST JSON_HEDLEY_PURE #endif #if defined(JSON_HEDLEY_RESTRICT) - #undef JSON_HEDLEY_RESTRICT -#endif -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT restrict -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) - #define JSON_HEDLEY_RESTRICT __restrict -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT _Restrict +#undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__cplusplus) +#define JSON_HEDLEY_RESTRICT restrict +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3, 1, 0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17, 10, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) || defined(__clang__) +#define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus) +#define JSON_HEDLEY_RESTRICT _Restrict #else - #define JSON_HEDLEY_RESTRICT +#define JSON_HEDLEY_RESTRICT #endif #if defined(JSON_HEDLEY_INLINE) - #undef JSON_HEDLEY_INLINE +#undef JSON_HEDLEY_INLINE #endif -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ (defined(__cplusplus) && (__cplusplus >= 199711L)) - #define JSON_HEDLEY_INLINE inline -#elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) - #define JSON_HEDLEY_INLINE __inline__ -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_INLINE __inline +#define JSON_HEDLEY_INLINE inline +#elif defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_ARM_VERSION_CHECK(6, 2, 0) +#define JSON_HEDLEY_INLINE __inline__ +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_INLINE __inline #else - #define JSON_HEDLEY_INLINE +#define JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_ALWAYS_INLINE) - #undef JSON_HEDLEY_ALWAYS_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) - #define JSON_HEDLEY_ALWAYS_INLINE __forceinline -#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_ALWAYS_INLINE \ + __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12, 0, 0) +#define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif JSON_HEDLEY_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus) +#define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") #else - #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE #endif #if defined(JSON_HEDLEY_NEVER_INLINE) - #undef JSON_HEDLEY_NEVER_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#undef JSON_HEDLEY_NEVER_INLINE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 10, 0) +#define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10, 2, 0) +#define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3, 2, 0) +#define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9, 0, 0) +#define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) #else - #define JSON_HEDLEY_NEVER_INLINE +#define JSON_HEDLEY_NEVER_INLINE #endif #if defined(JSON_HEDLEY_PRIVATE) - #undef JSON_HEDLEY_PRIVATE +#undef JSON_HEDLEY_PRIVATE #endif #if defined(JSON_HEDLEY_PUBLIC) - #undef JSON_HEDLEY_PUBLIC +#undef JSON_HEDLEY_PUBLIC #endif #if defined(JSON_HEDLEY_IMPORT) - #undef JSON_HEDLEY_IMPORT +#undef JSON_HEDLEY_IMPORT #endif #if defined(_WIN32) || defined(__CYGWIN__) - #define JSON_HEDLEY_PRIVATE - #define JSON_HEDLEY_PUBLIC __declspec(dllexport) - #define JSON_HEDLEY_IMPORT __declspec(dllimport) +#define JSON_HEDLEY_PRIVATE +#define JSON_HEDLEY_PUBLIC __declspec(dllexport) +#define JSON_HEDLEY_IMPORT __declspec(dllimport) #else - #if \ - JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) - #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) - #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) - #else - #define JSON_HEDLEY_PRIVATE - #define JSON_HEDLEY_PUBLIC - #endif - #define JSON_HEDLEY_IMPORT extern +#if JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8, 0, 0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_EABI__) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +#define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +#else +#define JSON_HEDLEY_PRIVATE +#define JSON_HEDLEY_PUBLIC +#endif +#define JSON_HEDLEY_IMPORT extern #endif #if defined(JSON_HEDLEY_NO_THROW) - #undef JSON_HEDLEY_NO_THROW -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#undef JSON_HEDLEY_NO_THROW +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 3, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) +#define JSON_HEDLEY_NO_THROW __declspec(nothrow) #else - #define JSON_HEDLEY_NO_THROW +#define JSON_HEDLEY_NO_THROW #endif #if defined(JSON_HEDLEY_FALL_THROUGH) - #undef JSON_HEDLEY_FALL_THROUGH +#undef JSON_HEDLEY_FALL_THROUGH #endif -#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) - #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough, 7, 0, 0) && \ + !defined(JSON_HEDLEY_PGI_VERSION) +#define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang, fallthrough) +#define JSON_HEDLEY_FALL_THROUGH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) #elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#define JSON_HEDLEY_FALL_THROUGH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) #elif defined(__fallthrough) /* SAL */ - #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#define JSON_HEDLEY_FALL_THROUGH __fallthrough #else - #define JSON_HEDLEY_FALL_THROUGH +#define JSON_HEDLEY_FALL_THROUGH #endif #if defined(JSON_HEDLEY_RETURNS_NON_NULL) - #undef JSON_HEDLEY_RETURNS_NON_NULL +#undef JSON_HEDLEY_RETURNS_NON_NULL #endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) - #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#if JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 9, 0) +#define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) #elif defined(_Ret_notnull_) /* SAL */ - #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ #else - #define JSON_HEDLEY_RETURNS_NON_NULL +#define JSON_HEDLEY_RETURNS_NON_NULL #endif #if defined(JSON_HEDLEY_ARRAY_PARAM) - #undef JSON_HEDLEY_ARRAY_PARAM -#endif -#if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && !defined(JSON_HEDLEY_TINYC_VERSION) +#define JSON_HEDLEY_ARRAY_PARAM(name) (name) #else - #define JSON_HEDLEY_ARRAY_PARAM(name) +#define JSON_HEDLEY_ARRAY_PARAM(name) #endif #if defined(JSON_HEDLEY_IS_CONSTANT) - #undef JSON_HEDLEY_IS_CONSTANT +#undef JSON_HEDLEY_IS_CONSTANT #endif #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) - #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#undef JSON_HEDLEY_REQUIRE_CONSTEXPR #endif /* JSON_HEDLEY_IS_CONSTEXPR_ is for HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ #if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #undef JSON_HEDLEY_IS_CONSTEXPR_ -#endif -#if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) - #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4, 1, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6, 1, 0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5, 10, 0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) +#define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) #endif #if !defined(__cplusplus) -# if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13, 1, 0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 4, 0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0, 9, 24) #if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + __builtin_types_compatible_p( \ + __typeof__((1 ? (void *)((__INTPTR_TYPE__)((expr)*0)) : (int *)0)), \ + int *) #else - #include - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) -#endif -# elif \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ - JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#include +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + __builtin_types_compatible_p( \ + __typeof__((1 ? (void *)((intptr_t)((expr)*0)) : (int *)0)), int *) +#endif +#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 9, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17, 0, 0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12, 1, 0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5, 3, 0) #if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + _Generic((1 ? (void *)((__INTPTR_TYPE__)((expr)*0)) : (int *)0), int * : 1, \ + void * : 0) #else - #include - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) -#endif -# elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - defined(JSON_HEDLEY_INTEL_VERSION) || \ - defined(JSON_HEDLEY_TINYC_VERSION) || \ - defined(JSON_HEDLEY_TI_VERSION) || \ - defined(__clang__) -# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ -((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) -# endif +#include +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + _Generic((1 ? (void *)((intptr_t)*0) : (int *)0), int * : 1, void * : 0) +#endif +#elif defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || defined(JSON_HEDLEY_TI_VERSION) || \ + defined(__clang__) +#define JSON_HEDLEY_IS_CONSTEXPR_(expr) \ + (sizeof(void) != sizeof(*(1 ? ((void *)((expr)*0L)) \ + : ((struct { char v[sizeof(void) * 2]; } *)1)))) +#endif #endif #if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#if !defined(JSON_HEDLEY_IS_CONSTANT) +#define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) +#endif +#define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) \ + (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) #else - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) (0) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#if !defined(JSON_HEDLEY_IS_CONSTANT) +#define JSON_HEDLEY_IS_CONSTANT(expr) (0) +#endif +#define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) #endif #if defined(JSON_HEDLEY_BEGIN_C_DECLS) - #undef JSON_HEDLEY_BEGIN_C_DECLS +#undef JSON_HEDLEY_BEGIN_C_DECLS #endif #if defined(JSON_HEDLEY_END_C_DECLS) - #undef JSON_HEDLEY_END_C_DECLS +#undef JSON_HEDLEY_END_C_DECLS #endif #if defined(JSON_HEDLEY_C_DECL) - #undef JSON_HEDLEY_C_DECL +#undef JSON_HEDLEY_C_DECL #endif #if defined(__cplusplus) - #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { - #define JSON_HEDLEY_END_C_DECLS } - #define JSON_HEDLEY_C_DECL extern "C" +#define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { +#define JSON_HEDLEY_END_C_DECLS } +#define JSON_HEDLEY_C_DECL extern "C" #else - #define JSON_HEDLEY_BEGIN_C_DECLS - #define JSON_HEDLEY_END_C_DECLS - #define JSON_HEDLEY_C_DECL +#define JSON_HEDLEY_BEGIN_C_DECLS +#define JSON_HEDLEY_END_C_DECLS +#define JSON_HEDLEY_C_DECL #endif #if defined(JSON_HEDLEY_STATIC_ASSERT) - #undef JSON_HEDLEY_STATIC_ASSERT -#endif -#if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if !defined(__cplusplus) && \ + ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6, 0, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) || defined(_Static_assert)) +#define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16, 0, 0) || \ + (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8, 3, 0)) +#define JSON_HEDLEY_STATIC_ASSERT(expr, message) \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_( \ + static_assert(expr, message)) #else -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#define JSON_HEDLEY_STATIC_ASSERT(expr, message) #endif #if defined(JSON_HEDLEY_CONST_CAST) - #undef JSON_HEDLEY_CONST_CAST +#undef JSON_HEDLEY_CONST_CAST #endif #if defined(__cplusplus) -# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ - JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) +#define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4, 6, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_CONST_CAST(T, expr) \ + (__extension__({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL((T)(expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) #else -# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#define JSON_HEDLEY_CONST_CAST(T, expr) ((T)(expr)) #endif #if defined(JSON_HEDLEY_REINTERPRET_CAST) - #undef JSON_HEDLEY_REINTERPRET_CAST +#undef JSON_HEDLEY_REINTERPRET_CAST #endif #if defined(__cplusplus) - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) #else - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) +#define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T *)&(expr))) #endif #if defined(JSON_HEDLEY_STATIC_CAST) - #undef JSON_HEDLEY_STATIC_CAST +#undef JSON_HEDLEY_STATIC_CAST #endif #if defined(__cplusplus) - #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) #else - #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#define JSON_HEDLEY_STATIC_CAST(T, expr) ((T)(expr)) #endif #if defined(JSON_HEDLEY_CPP_CAST) - #undef JSON_HEDLEY_CPP_CAST +#undef JSON_HEDLEY_CPP_CAST #endif #if defined(__cplusplus) - #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) +#define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) #else - #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#define JSON_HEDLEY_CPP_CAST(T, expr) (expr) #endif #if defined(JSON_HEDLEY_NULL) - #undef JSON_HEDLEY_NULL +#undef JSON_HEDLEY_NULL #endif #if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) - #elif defined(NULL) - #define JSON_HEDLEY_NULL NULL - #else - #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) - #endif +#if __cplusplus >= 201103L +#define JSON_HEDLEY_NULL \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) +#elif defined(NULL) +#define JSON_HEDLEY_NULL NULL +#else +#define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void *, 0) +#endif #elif defined(NULL) - #define JSON_HEDLEY_NULL NULL +#define JSON_HEDLEY_NULL NULL #else - #define JSON_HEDLEY_NULL ((void*) 0) +#define JSON_HEDLEY_NULL ((void *)0) #endif #if defined(JSON_HEDLEY_MESSAGE) - #undef JSON_HEDLEY_MESSAGE +#undef JSON_HEDLEY_MESSAGE #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_MESSAGE(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(message msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) -#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 4, 0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2, 0, 0) +#define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else -# define JSON_HEDLEY_MESSAGE(msg) +#define JSON_HEDLEY_MESSAGE(msg) #endif #if defined(JSON_HEDLEY_WARNING) - #undef JSON_HEDLEY_WARNING +#undef JSON_HEDLEY_WARNING #endif #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_WARNING(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(clang warning msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4, 8, 0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18, 4, 0) +#define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15, 0, 0) +#define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) #else -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) #endif #if defined(JSON_HEDLEY_REQUIRE) - #undef JSON_HEDLEY_REQUIRE +#undef JSON_HEDLEY_REQUIRE #endif #if defined(JSON_HEDLEY_REQUIRE_MSG) - #undef JSON_HEDLEY_REQUIRE_MSG +#undef JSON_HEDLEY_REQUIRE_MSG #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) -# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") -# define JSON_HEDLEY_REQUIRE(expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) -# endif +#if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +#define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#else +#define JSON_HEDLEY_REQUIRE(expr) \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) +#define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \ + __attribute__((diagnose_if(!(expr), msg, "error"))) +#endif #else -# define JSON_HEDLEY_REQUIRE(expr) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#define JSON_HEDLEY_REQUIRE(expr) +#define JSON_HEDLEY_REQUIRE_MSG(expr, msg) #endif #if defined(JSON_HEDLEY_FLAGS) - #undef JSON_HEDLEY_FLAGS +#undef JSON_HEDLEY_FLAGS #endif #if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) - #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) #endif #if defined(JSON_HEDLEY_FLAGS_CAST) - #undef JSON_HEDLEY_FLAGS_CAST -#endif -#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) -# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) +#undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19, 0, 0) +#define JSON_HEDLEY_FLAGS_CAST(T, expr) \ + (__extension__({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)")((T)(expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) #else -# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) #endif #if defined(JSON_HEDLEY_EMPTY_BASES) - #undef JSON_HEDLEY_EMPTY_BASES +#undef JSON_HEDLEY_EMPTY_BASES #endif -#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) - #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19, 0, 23918) && \ + !JSON_HEDLEY_MSVC_VERSION_CHECK(20, 0, 0) +#define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) #else - #define JSON_HEDLEY_EMPTY_BASES +#define JSON_HEDLEY_EMPTY_BASES #endif /* Remaining macros are deprecated. */ #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK #endif #if defined(__clang__) - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) (0) #else - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major, minor, patch) \ + JSON_HEDLEY_GCC_VERSION_CHECK(major, minor, patch) #endif #if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE #endif -#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) \ + JSON_HEDLEY_HAS_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE #endif -#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) \ + JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) - #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#undef JSON_HEDLEY_CLANG_HAS_BUILTIN #endif #define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) #if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) - #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#undef JSON_HEDLEY_CLANG_HAS_FEATURE #endif #define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) #if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) - #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#undef JSON_HEDLEY_CLANG_HAS_EXTENSION #endif -#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) \ + JSON_HEDLEY_HAS_EXTENSION(extension) #if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE #endif -#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) \ + JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) #if defined(JSON_HEDLEY_CLANG_HAS_WARNING) - #undef JSON_HEDLEY_CLANG_HAS_WARNING +#undef JSON_HEDLEY_CLANG_HAS_WARNING #endif #define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ - // This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of +// them // exclude unsupported compilers #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) - #if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #endif +#if defined(__clang__) +#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < \ + 30400 +#error \ + "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) +#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 +#error \ + "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +#endif +#endif #endif // C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 +#if (defined(__cplusplus) && __cplusplus >= 201703L) || \ + (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 +#define JSON_HAS_CPP_17 +#define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (defined(_HAS_CXX14) && _HAS_CXX14 == 1) +#define JSON_HAS_CPP_14 #endif // disable float-equal warnings on GCC/clang #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" #endif // disable documentation warnings on clang #if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdocumentation" #endif // allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) - #define JSON_INTERNAL_CATCH(exception) catch(exception) +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \ + defined(_CPPUNWIND)) && \ + !defined(JSON_NOEXCEPTION) +#define JSON_THROW(exception) throw exception +#define JSON_TRY try +#define JSON_CATCH(exception) catch (exception) +#define JSON_INTERNAL_CATCH(exception) catch (exception) #else - #include - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) - #define JSON_INTERNAL_CATCH(exception) if(false) +#include +#define JSON_THROW(exception) std::abort() +#define JSON_TRY if (true) +#define JSON_CATCH(exception) if (false) +#define JSON_INTERNAL_CATCH(exception) if (false) #endif // override exception macros #if defined(JSON_THROW_USER) - #undef JSON_THROW - #define JSON_THROW JSON_THROW_USER +#undef JSON_THROW +#define JSON_THROW JSON_THROW_USER #endif #if defined(JSON_TRY_USER) - #undef JSON_TRY - #define JSON_TRY JSON_TRY_USER +#undef JSON_TRY +#define JSON_TRY JSON_TRY_USER #endif #if defined(JSON_CATCH_USER) - #undef JSON_CATCH - #define JSON_CATCH JSON_CATCH_USER - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#undef JSON_CATCH +#define JSON_CATCH JSON_CATCH_USER +#undef JSON_INTERNAL_CATCH +#define JSON_INTERNAL_CATCH JSON_CATCH_USER #endif #if defined(JSON_INTERNAL_CATCH_USER) - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#undef JSON_INTERNAL_CATCH +#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif /*! @@ -1782,53 +1928,50 @@ JSON_HEDLEY_DIAGNOSTIC_POP @def NLOHMANN_JSON_SERIALIZE_ENUM @since version 3.4.0 */ -#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ - template \ - inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [e](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.first == e; \ - }); \ - j = ((it != std::end(m)) ? it : std::begin(m))->second; \ - } \ - template \ - inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [&j](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.second == j; \ - }); \ - e = ((it != std::end(m)) ? it : std::begin(m))->first; \ - } +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType &j, const ENUM_TYPE &e) { \ + static_assert(std::is_enum::value, \ + #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if( \ + std::begin(m), std::end(m), \ + [e](const std::pair &ej_pair) -> bool { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType &j, ENUM_TYPE &e) { \ + static_assert(std::is_enum::value, \ + #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if( \ + std::begin(m), std::end(m), \ + [&j](const std::pair &ej_pair) -> bool { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } // Ugly macros to avoid uglier copy-paste when specializing basic_json. They // may be removed in the future once the class is split. -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - - -namespace nlohmann -{ -namespace detail -{ +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template