//
// httplib.h
//
-// Copyright (c) 2023 Yuji Hirose. All rights reserved.
+// Copyright (c) 2024 Yuji Hirose. All rights reserved.
// MIT License
//
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
-#define CPPHTTPLIB_VERSION "0.12.2"
+#define CPPHTTPLIB_VERSION "0.15.3"
/*
* Configuration
#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192
#endif
+#ifndef CPPHTTPLIB_RANGE_MAX_COUNT
+#define CPPHTTPLIB_RANGE_MAX_COUNT 1024
+#endif
+
#ifndef CPPHTTPLIB_TCP_NODELAY
#define CPPHTTPLIB_TCP_NODELAY false
#endif
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif
-#ifndef strcasecmp
-#define strcasecmp _stricmp
-#endif // strcasecmp
-
using socket_t = SOCKET;
#ifdef CPPHTTPLIB_USE_POLL
#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
#else // not _WIN32
#include <arpa/inet.h>
-#ifndef _AIX
+#if !defined(_AIX) && !defined(__MVS__)
#include <ifaddrs.h>
#endif
+#ifdef __MVS__
+#include <strings.h>
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#endif
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#endif
#include <csignal>
#include <pthread.h>
+#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <condition_variable>
#include <cstring>
#include <errno.h>
+#include <exception>
#include <fcntl.h>
#include <fstream>
#include <functional>
#include <string>
#include <sys/stat.h>
#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
#ifdef _WIN32
#ifdef _MSC_VER
#pragma comment(lib, "crypt32.lib")
-#pragma comment(lib, "cryptui.lib")
#endif
#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
#include <TargetConditionals.h>
#include <iostream>
#include <sstream>
-#if OPENSSL_VERSION_NUMBER < 0x1010100fL
-#error Sorry, OpenSSL versions prior to 1.1.1 are not supported
-#elif OPENSSL_VERSION_NUMBER < 0x30000000L
-#define SSL_get1_peer_certificate SSL_get_peer_certificate
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+#error Sorry, OpenSSL versions prior to 3.0.0 are not supported
#endif
#endif
explicit scope_exit(std::function<void(void)> &&f)
: exit_function(std::move(f)), execute_on_destruction{true} {}
- scope_exit(scope_exit &&rhs)
+ scope_exit(scope_exit &&rhs) noexcept
: exit_function(std::move(rhs.exit_function)),
execute_on_destruction{rhs.execute_on_destruction} {
rhs.release();
} // namespace detail
+enum StatusCode {
+ // Information responses
+ Continue_100 = 100,
+ SwitchingProtocol_101 = 101,
+ Processing_102 = 102,
+ EarlyHints_103 = 103,
+
+ // Successful responses
+ OK_200 = 200,
+ Created_201 = 201,
+ Accepted_202 = 202,
+ NonAuthoritativeInformation_203 = 203,
+ NoContent_204 = 204,
+ ResetContent_205 = 205,
+ PartialContent_206 = 206,
+ MultiStatus_207 = 207,
+ AlreadyReported_208 = 208,
+ IMUsed_226 = 226,
+
+ // Redirection messages
+ MultipleChoices_300 = 300,
+ MovedPermanently_301 = 301,
+ Found_302 = 302,
+ SeeOther_303 = 303,
+ NotModified_304 = 304,
+ UseProxy_305 = 305,
+ unused_306 = 306,
+ TemporaryRedirect_307 = 307,
+ PermanentRedirect_308 = 308,
+
+ // Client error responses
+ BadRequest_400 = 400,
+ Unauthorized_401 = 401,
+ PaymentRequired_402 = 402,
+ Forbidden_403 = 403,
+ NotFound_404 = 404,
+ MethodNotAllowed_405 = 405,
+ NotAcceptable_406 = 406,
+ ProxyAuthenticationRequired_407 = 407,
+ RequestTimeout_408 = 408,
+ Conflict_409 = 409,
+ Gone_410 = 410,
+ LengthRequired_411 = 411,
+ PreconditionFailed_412 = 412,
+ PayloadTooLarge_413 = 413,
+ UriTooLong_414 = 414,
+ UnsupportedMediaType_415 = 415,
+ RangeNotSatisfiable_416 = 416,
+ ExpectationFailed_417 = 417,
+ ImATeapot_418 = 418,
+ MisdirectedRequest_421 = 421,
+ UnprocessableContent_422 = 422,
+ Locked_423 = 423,
+ FailedDependency_424 = 424,
+ TooEarly_425 = 425,
+ UpgradeRequired_426 = 426,
+ PreconditionRequired_428 = 428,
+ TooManyRequests_429 = 429,
+ RequestHeaderFieldsTooLarge_431 = 431,
+ UnavailableForLegalReasons_451 = 451,
+
+ // Server error responses
+ InternalServerError_500 = 500,
+ NotImplemented_501 = 501,
+ BadGateway_502 = 502,
+ ServiceUnavailable_503 = 503,
+ GatewayTimeout_504 = 504,
+ HttpVersionNotSupported_505 = 505,
+ VariantAlsoNegotiates_506 = 506,
+ InsufficientStorage_507 = 507,
+ LoopDetected_508 = 508,
+ NotExtended_510 = 510,
+ NetworkAuthenticationRequired_511 = 511,
+};
+
using Headers = std::multimap<std::string, std::string, detail::ci>;
using Params = std::multimap<std::string, std::string>;
DataSink &operator=(DataSink &&) = delete;
std::function<bool(const char *data, size_t data_len)> write;
+ std::function<bool()> is_writable;
std::function<void()> done;
std::function<void(const Headers &trailer)> done_with_trailer;
std::ostream os;
private:
- class data_sink_streambuf : public std::streambuf {
+ class data_sink_streambuf final : public std::streambuf {
public:
explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}
protected:
- std::streamsize xsputn(const char *s, std::streamsize n) {
+ std::streamsize xsputn(const char *s, std::streamsize n) override {
sink_.write(s, static_cast<size_t>(n));
return n;
}
MultipartFormDataMap files;
Ranges ranges;
Match matches;
+ std::unordered_map<std::string, std::string> path_params;
// for client
ResponseHandler response_handler;
bool has_header(const std::string &key) const;
std::string get_header_value(const std::string &key, size_t id = 0) const;
- template <typename T>
- T get_header_value(const std::string &key, size_t id = 0) const;
+ uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
size_t get_header_value_count(const std::string &key) const;
void set_header(const std::string &key, const std::string &val);
bool has_header(const std::string &key) const;
std::string get_header_value(const std::string &key, size_t id = 0) const;
- template <typename T>
- T get_header_value(const std::string &key, size_t id = 0) const;
+ uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
size_t get_header_value_count(const std::string &key) const;
void set_header(const std::string &key, const std::string &val);
- void set_redirect(const std::string &url, int status = 302);
+ void set_redirect(const std::string &url, int status = StatusCode::Found_302);
void set_content(const char *s, size_t n, const std::string &content_type);
void set_content(const std::string &s, const std::string &content_type);
+ void set_content(std::string &&s, const std::string &content_type);
void set_content_provider(
size_t length, const std::string &content_type, ContentProvider provider,
TaskQueue() = default;
virtual ~TaskQueue() = default;
- virtual void enqueue(std::function<void()> fn) = 0;
+ virtual bool enqueue(std::function<void()> fn) = 0;
virtual void shutdown() = 0;
virtual void on_idle() {}
};
-class ThreadPool : public TaskQueue {
+class ThreadPool final : public TaskQueue {
public:
- explicit ThreadPool(size_t n) : shutdown_(false) {
+ explicit ThreadPool(size_t n, size_t mqr = 0)
+ : shutdown_(false), max_queued_requests_(mqr) {
while (n) {
threads_.emplace_back(worker(*this));
n--;
ThreadPool(const ThreadPool &) = delete;
~ThreadPool() override = default;
- void enqueue(std::function<void()> fn) override {
+ bool enqueue(std::function<void()> fn) override {
{
std::unique_lock<std::mutex> lock(mutex_);
+ if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) {
+ return false;
+ }
jobs_.push_back(std::move(fn));
}
cond_.notify_one();
+ return true;
}
void shutdown() override {
std::list<std::function<void()>> jobs_;
bool shutdown_;
+ size_t max_queued_requests_ = 0;
std::condition_variable cond_;
std::mutex mutex_;
void default_socket_options(socket_t sock);
+const char *status_message(int status);
+
+std::string get_bearer_token_auth(const Request &req);
+
+namespace detail {
+
+class MatcherBase {
+public:
+ virtual ~MatcherBase() = default;
+
+ // Match request path and populate its matches and
+ virtual bool match(Request &request) const = 0;
+};
+
+/**
+ * Captures parameters in request path and stores them in Request::path_params
+ *
+ * Capture name is a substring of a pattern from : to /.
+ * The rest of the pattern is matched agains the request path directly
+ * Parameters are captured starting from the next character after
+ * the end of the last matched static pattern fragment until the next /.
+ *
+ * Example pattern:
+ * "/path/fragments/:capture/more/fragments/:second_capture"
+ * Static fragments:
+ * "/path/fragments/", "more/fragments/"
+ *
+ * Given the following request path:
+ * "/path/fragments/:1/more/fragments/:2"
+ * the resulting capture will be
+ * {{"capture", "1"}, {"second_capture", "2"}}
+ */
+class PathParamsMatcher final : public MatcherBase {
+public:
+ PathParamsMatcher(const std::string &pattern);
+
+ bool match(Request &request) const override;
+
+private:
+ static constexpr char marker = ':';
+ // Treat segment separators as the end of path parameter capture
+ // Does not need to handle query parameters as they are parsed before path
+ // matching
+ static constexpr char separator = '/';
+
+ // Contains static path fragments to match against, excluding the '/' after
+ // path params
+ // Fragments are separated by path params
+ std::vector<std::string> static_fragments_;
+ // Stores the names of the path parameters to be used as keys in the
+ // Request::path_params map
+ std::vector<std::string> param_names_;
+};
+
+/**
+ * Performs std::regex_match on request path
+ * and stores the result in Request::matches
+ *
+ * Note that regex match is performed directly on the whole request.
+ * This means that wildcard patterns may match multiple path segments with /:
+ * "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end".
+ */
+class RegexMatcher final : public MatcherBase {
+public:
+ RegexMatcher(const std::string &pattern) : regex_(pattern) {}
+
+ bool match(Request &request) const override;
+
+private:
+ std::regex regex_;
+};
+
+ssize_t write_headers(Stream &strm, const Headers &headers);
+
+} // namespace detail
+
class Server {
public:
using Handler = std::function<void(const Request &, Response &)>;
bool remove_mount_point(const std::string &mount_point);
Server &set_file_extension_and_mimetype_mapping(const std::string &ext,
const std::string &mime);
+ Server &set_default_file_mimetype(const std::string &mime);
Server &set_file_request_handler(Handler handler);
Server &set_error_handler(HandlerWithResponse handler);
Server &set_socket_options(SocketOptions socket_options);
Server &set_default_headers(Headers headers);
+ Server &
+ set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
Server &set_keep_alive_max_count(size_t count);
Server &set_keep_alive_timeout(time_t sec);
size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
private:
- using Handlers = std::vector<std::pair<std::regex, Handler>>;
+ using Handlers =
+ std::vector<std::pair<std::unique_ptr<detail::MatcherBase>, Handler>>;
using HandlersForContentReader =
- std::vector<std::pair<std::regex, HandlerWithContentReader>>;
+ std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
+ HandlerWithContentReader>>;
+
+ static std::unique_ptr<detail::MatcherBase>
+ make_matcher(const std::string &pattern);
socket_t create_server_socket(const std::string &host, int port,
int socket_flags,
bool routing(Request &req, Response &res, Stream &strm);
bool handle_file_request(const Request &req, Response &res,
bool head = false);
- bool dispatch_request(Request &req, Response &res, const Handlers &handlers);
- bool
- dispatch_request_for_content_reader(Request &req, Response &res,
- ContentReader content_reader,
- const HandlersForContentReader &handlers);
+ bool dispatch_request(Request &req, Response &res,
+ const Handlers &handlers) const;
+ bool dispatch_request_for_content_reader(
+ Request &req, Response &res, ContentReader content_reader,
+ const HandlersForContentReader &handlers) const;
- bool parse_request_line(const char *s, Request &req);
+ bool parse_request_line(const char *s, Request &req) const;
void apply_ranges(const Request &req, Response &res,
- std::string &content_type, std::string &boundary);
- bool write_response(Stream &strm, bool close_connection, const Request &req,
+ std::string &content_type, std::string &boundary) const;
+ bool write_response(Stream &strm, bool close_connection, Request &req,
Response &res);
bool write_response_with_content(Stream &strm, bool close_connection,
const Request &req, Response &res);
bool read_content_core(Stream &strm, Request &req, Response &res,
ContentReceiver receiver,
MultipartContentHeader multipart_header,
- ContentReceiver multipart_receiver);
+ ContentReceiver multipart_receiver) const;
virtual bool process_and_close_socket(socket_t sock);
+ std::atomic<bool> is_running_{false};
+ std::atomic<bool> done_{false};
+
struct MountPointEntry {
std::string mount_point;
std::string base_dir;
Headers headers;
};
std::vector<MountPointEntry> base_dirs_;
-
- std::atomic<bool> is_running_{false};
- std::atomic<bool> done_{false};
std::map<std::string, std::string> file_extension_and_mimetype_map_;
+ std::string default_file_mimetype_ = "application/octet-stream";
Handler file_request_handler_;
+
Handlers get_handlers_;
Handlers post_handlers_;
HandlersForContentReader post_handlers_for_content_reader_;
Handlers delete_handlers_;
HandlersForContentReader delete_handlers_for_content_reader_;
Handlers options_handlers_;
+
HandlerWithResponse error_handler_;
ExceptionHandler exception_handler_;
HandlerWithResponse pre_routing_handler_;
Handler post_routing_handler_;
- Logger logger_;
Expect100ContinueHandler expect_100_continue_handler_;
+ Logger logger_;
+
int address_family_ = AF_UNSPEC;
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
SocketOptions socket_options_ = default_socket_options;
Headers default_headers_;
+ std::function<ssize_t(Stream &, Headers &)> header_writer_ =
+ detail::write_headers;
};
enum class Error {
UnsupportedMultipartBoundaryChars,
Compression,
ConnectionTimeout,
+ ProxyConnection,
// For internal use only
SSLPeerCouldBeClosed_,
};
-std::string to_string(const Error error);
+std::string to_string(Error error);
std::ostream &operator<<(std::ostream &os, const Error &obj);
class Result {
public:
+ Result() = default;
Result(std::unique_ptr<Response> &&res, Error err,
Headers &&request_headers = Headers{})
: res_(std::move(res)), err_(err),
bool has_request_header(const std::string &key) const;
std::string get_request_header_value(const std::string &key,
size_t id = 0) const;
- template <typename T>
- T get_request_header_value(const std::string &key, size_t id = 0) const;
+ uint64_t get_request_header_value_u64(const std::string &key,
+ size_t id = 0) const;
size_t get_request_header_value_count(const std::string &key) const;
private:
std::unique_ptr<Response> res_;
- Error err_;
+ Error err_ = Error::Unknown;
Headers request_headers_;
};
bool send(Request &req, Response &res, Error &error);
Result send(const Request &req);
- size_t is_socket_open() const;
+ void stop();
- socket_t socket() const;
+ std::string host() const;
+ int port() const;
- void stop();
+ size_t is_socket_open() const;
+ socket_t socket() const;
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
void set_default_headers(Headers headers);
+ void
+ set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
+
void set_address_family(int family);
void set_tcp_nodelay(bool on);
void set_socket_options(SocketOptions socket_options);
void set_ca_cert_path(const std::string &ca_cert_file_path,
const std::string &ca_cert_dir_path = std::string());
void set_ca_cert_store(X509_STORE *ca_cert_store);
+ X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const;
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
// Also, shutdown_ssl and close_socket should also NOT be called concurrently
// with a DIFFERENT thread sending requests using that socket.
virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully);
- void shutdown_socket(Socket &socket);
+ void shutdown_socket(Socket &socket) const;
void close_socket(Socket &socket);
bool process_request(Stream &strm, Request &req, Response &res,
bool close_connection, Error &error);
bool write_content_with_provider(Stream &strm, const Request &req,
- Error &error);
+ Error &error) const;
void copy_settings(const ClientImpl &rhs);
// Default headers
Headers default_headers_;
+ // Header writer
+ std::function<ssize_t(Stream &, Headers &)> header_writer_ =
+ detail::write_headers;
+
// Settings
std::string client_cert_path_;
std::string client_key_path_;
Result send_(Request &&req);
socket_t create_client_socket(Error &error) const;
- bool read_response_line(Stream &strm, const Request &req, Response &res);
+ bool read_response_line(Stream &strm, const Request &req,
+ Response &res) const;
bool write_request(Stream &strm, Request &req, bool close_connection,
Error &error);
bool redirect(Request &req, Response &res, Error &error);
const std::string &content_type);
ContentProviderWithoutLength get_multipart_content_provider(
const std::string &boundary, const MultipartFormDataItems &items,
- const MultipartFormDataProviderItems &provider_items);
+ const MultipartFormDataProviderItems &provider_items) const;
std::string adjust_host_string(const std::string &host) const;
bool send(Request &req, Response &res, Error &error);
Result send(const Request &req);
- size_t is_socket_open() const;
+ void stop();
- socket_t socket() const;
+ std::string host() const;
+ int port() const;
- void stop();
+ size_t is_socket_open() const;
+ socket_t socket() const;
void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
void set_default_headers(Headers headers);
+ void
+ set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
+
void set_address_family(int family);
void set_tcp_nodelay(bool on);
void set_socket_options(SocketOptions socket_options);
const std::string &ca_cert_dir_path = std::string());
void set_ca_cert_store(X509_STORE *ca_cert_store);
+ void load_ca_cert_store(const char *ca_cert, std::size_t size);
long get_openssl_verify_result() const;
std::mutex ctx_mutex_;
};
-class SSLClient : public ClientImpl {
+class SSLClient final : public ClientImpl {
public:
explicit SSLClient(const std::string &host);
explicit SSLClient(const std::string &host, int port,
const std::string &client_cert_path,
- const std::string &client_key_path);
+ const std::string &client_key_path,
+ const std::string &private_key_password = std::string());
explicit SSLClient(const std::string &host, int port, X509 *client_cert,
- EVP_PKEY *client_key);
+ EVP_PKEY *client_key,
+ const std::string &private_key_password = std::string());
~SSLClient() override;
bool is_valid() const override;
void set_ca_cert_store(X509_STORE *ca_cert_store);
+ void load_ca_cert_store(const char *ca_cert, std::size_t size);
long get_openssl_verify_result() const;
private:
bool create_and_connect_socket(Socket &socket, Error &error) override;
void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
- void shutdown_ssl_impl(Socket &socket, bool shutdown_socket);
+ void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully);
bool process_socket(const Socket &socket,
std::function<bool(Stream &strm)> callback) override;
callback(static_cast<time_t>(sec), static_cast<time_t>(usec));
}
-template <typename T>
-inline T get_header_value(const Headers & /*headers*/,
- const std::string & /*key*/, size_t /*id*/ = 0,
- uint64_t /*def*/ = 0) {}
-
-template <>
-inline uint64_t get_header_value<uint64_t>(const Headers &headers,
- const std::string &key, size_t id,
- uint64_t def) {
+inline uint64_t get_header_value_u64(const Headers &headers,
+ const std::string &key, size_t id,
+ uint64_t def) {
auto rng = headers.equal_range(key);
auto it = rng.first;
std::advance(it, static_cast<ssize_t>(id));
} // namespace detail
-template <typename T>
-inline T Request::get_header_value(const std::string &key, size_t id) const {
- return detail::get_header_value<T>(headers, key, id, 0);
+inline uint64_t Request::get_header_value_u64(const std::string &key,
+ size_t id) const {
+ return detail::get_header_value_u64(headers, key, id, 0);
}
-template <typename T>
-inline T Response::get_header_value(const std::string &key, size_t id) const {
- return detail::get_header_value<T>(headers, key, id, 0);
+inline uint64_t Response::get_header_value_u64(const std::string &key,
+ size_t id) const {
+ return detail::get_header_value_u64(headers, key, id, 0);
}
template <typename... Args>
inline void default_socket_options(socket_t sock) {
int yes = 1;
#ifdef _WIN32
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes),
- sizeof(yes));
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ reinterpret_cast<const char *>(&yes), sizeof(yes));
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
- reinterpret_cast<char *>(&yes), sizeof(yes));
+ reinterpret_cast<const char *>(&yes), sizeof(yes));
#else
#ifdef SO_REUSEPORT
- setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, reinterpret_cast<void *>(&yes),
- sizeof(yes));
+ setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
+ reinterpret_cast<const void *>(&yes), sizeof(yes));
#else
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<void *>(&yes),
- sizeof(yes));
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ reinterpret_cast<const void *>(&yes), sizeof(yes));
#endif
#endif
}
+inline const char *status_message(int status) {
+ switch (status) {
+ case StatusCode::Continue_100: return "Continue";
+ case StatusCode::SwitchingProtocol_101: return "Switching Protocol";
+ case StatusCode::Processing_102: return "Processing";
+ case StatusCode::EarlyHints_103: return "Early Hints";
+ case StatusCode::OK_200: return "OK";
+ case StatusCode::Created_201: return "Created";
+ case StatusCode::Accepted_202: return "Accepted";
+ case StatusCode::NonAuthoritativeInformation_203:
+ return "Non-Authoritative Information";
+ case StatusCode::NoContent_204: return "No Content";
+ case StatusCode::ResetContent_205: return "Reset Content";
+ case StatusCode::PartialContent_206: return "Partial Content";
+ case StatusCode::MultiStatus_207: return "Multi-Status";
+ case StatusCode::AlreadyReported_208: return "Already Reported";
+ case StatusCode::IMUsed_226: return "IM Used";
+ case StatusCode::MultipleChoices_300: return "Multiple Choices";
+ case StatusCode::MovedPermanently_301: return "Moved Permanently";
+ case StatusCode::Found_302: return "Found";
+ case StatusCode::SeeOther_303: return "See Other";
+ case StatusCode::NotModified_304: return "Not Modified";
+ case StatusCode::UseProxy_305: return "Use Proxy";
+ case StatusCode::unused_306: return "unused";
+ case StatusCode::TemporaryRedirect_307: return "Temporary Redirect";
+ case StatusCode::PermanentRedirect_308: return "Permanent Redirect";
+ case StatusCode::BadRequest_400: return "Bad Request";
+ case StatusCode::Unauthorized_401: return "Unauthorized";
+ case StatusCode::PaymentRequired_402: return "Payment Required";
+ case StatusCode::Forbidden_403: return "Forbidden";
+ case StatusCode::NotFound_404: return "Not Found";
+ case StatusCode::MethodNotAllowed_405: return "Method Not Allowed";
+ case StatusCode::NotAcceptable_406: return "Not Acceptable";
+ case StatusCode::ProxyAuthenticationRequired_407:
+ return "Proxy Authentication Required";
+ case StatusCode::RequestTimeout_408: return "Request Timeout";
+ case StatusCode::Conflict_409: return "Conflict";
+ case StatusCode::Gone_410: return "Gone";
+ case StatusCode::LengthRequired_411: return "Length Required";
+ case StatusCode::PreconditionFailed_412: return "Precondition Failed";
+ case StatusCode::PayloadTooLarge_413: return "Payload Too Large";
+ case StatusCode::UriTooLong_414: return "URI Too Long";
+ case StatusCode::UnsupportedMediaType_415: return "Unsupported Media Type";
+ case StatusCode::RangeNotSatisfiable_416: return "Range Not Satisfiable";
+ case StatusCode::ExpectationFailed_417: return "Expectation Failed";
+ case StatusCode::ImATeapot_418: return "I'm a teapot";
+ case StatusCode::MisdirectedRequest_421: return "Misdirected Request";
+ case StatusCode::UnprocessableContent_422: return "Unprocessable Content";
+ case StatusCode::Locked_423: return "Locked";
+ case StatusCode::FailedDependency_424: return "Failed Dependency";
+ case StatusCode::TooEarly_425: return "Too Early";
+ case StatusCode::UpgradeRequired_426: return "Upgrade Required";
+ case StatusCode::PreconditionRequired_428: return "Precondition Required";
+ case StatusCode::TooManyRequests_429: return "Too Many Requests";
+ case StatusCode::RequestHeaderFieldsTooLarge_431:
+ return "Request Header Fields Too Large";
+ case StatusCode::UnavailableForLegalReasons_451:
+ return "Unavailable For Legal Reasons";
+ case StatusCode::NotImplemented_501: return "Not Implemented";
+ case StatusCode::BadGateway_502: return "Bad Gateway";
+ case StatusCode::ServiceUnavailable_503: return "Service Unavailable";
+ case StatusCode::GatewayTimeout_504: return "Gateway Timeout";
+ case StatusCode::HttpVersionNotSupported_505:
+ return "HTTP Version Not Supported";
+ case StatusCode::VariantAlsoNegotiates_506: return "Variant Also Negotiates";
+ case StatusCode::InsufficientStorage_507: return "Insufficient Storage";
+ case StatusCode::LoopDetected_508: return "Loop Detected";
+ case StatusCode::NotExtended_510: return "Not Extended";
+ case StatusCode::NetworkAuthenticationRequired_511:
+ return "Network Authentication Required";
+
+ default:
+ case StatusCode::InternalServerError_500: return "Internal Server Error";
+ }
+}
+
+inline std::string get_bearer_token_auth(const Request &req) {
+ if (req.has_header("Authorization")) {
+ static std::string BearerHeaderPrefix = "Bearer ";
+ return req.get_header_value("Authorization")
+ .substr(BearerHeaderPrefix.length());
+ }
+ return "";
+}
+
template <class Rep, class Period>
inline Server &
Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
return "Unsupported HTTP multipart boundary characters";
case Error::Compression: return "Compression failed";
case Error::ConnectionTimeout: return "Connection timed out";
+ case Error::ProxyConnection: return "Proxy connection failed";
case Error::Unknown: return "Unknown";
default: break;
}
return os;
}
-template <typename T>
-inline T Result::get_request_header_value(const std::string &key,
- size_t id) const {
- return detail::get_header_value<T>(request_headers_, key, id, 0);
+inline uint64_t Result::get_request_header_value_u64(const std::string &key,
+ size_t id) const {
+ return detail::get_header_value_u64(request_headers_, key, id, 0);
}
template <class Rep, class Period>
std::string append_query_params(const std::string &path, const Params ¶ms);
-std::pair<std::string, std::string> make_range_header(Ranges ranges);
+std::pair<std::string, std::string> make_range_header(const Ranges &ranges);
std::pair<std::string, std::string>
make_basic_authentication_header(const std::string &username,
void split(const char *b, const char *e, char d,
std::function<void(const char *, const char *)> fn);
+void split(const char *b, const char *e, char d, size_t m,
+ std::function<void(const char *, const char *)> fn);
+
bool process_client_socket(socket_t sock, time_t read_timeout_sec,
time_t read_timeout_usec, time_t write_timeout_sec,
time_t write_timeout_usec,
EncodingType encoding_type(const Request &req, const Response &res);
-class BufferStream : public Stream {
+class BufferStream final : public Stream {
public:
BufferStream() = default;
~BufferStream() override = default;
Callback callback) = 0;
};
-class nocompressor : public compressor {
+class nocompressor final : public compressor {
public:
- virtual ~nocompressor() = default;
+ ~nocompressor() override = default;
bool compress(const char *data, size_t data_length, bool /*last*/,
Callback callback) override;
};
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
-class gzip_compressor : public compressor {
+class gzip_compressor final : public compressor {
public:
gzip_compressor();
- ~gzip_compressor();
+ ~gzip_compressor() override;
bool compress(const char *data, size_t data_length, bool last,
Callback callback) override;
z_stream strm_;
};
-class gzip_decompressor : public decompressor {
+class gzip_decompressor final : public decompressor {
public:
gzip_decompressor();
- ~gzip_decompressor();
+ ~gzip_decompressor() override;
bool is_valid() const override;
#endif
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
-class brotli_compressor : public compressor {
+class brotli_compressor final : public compressor {
public:
brotli_compressor();
~brotli_compressor();
BrotliEncoderState *state_ = nullptr;
};
-class brotli_decompressor : public decompressor {
+class brotli_decompressor final : public decompressor {
public:
brotli_decompressor();
~brotli_decompressor();
std::string glowable_buffer_;
};
+class mmap {
+public:
+ mmap(const char *path);
+ ~mmap();
+
+ bool open(const char *path);
+ void close();
+
+ bool is_open() const;
+ size_t size() const;
+ const char *data() const;
+
+private:
+#if defined(_WIN32)
+ HANDLE hFile_;
+ HANDLE hMapping_;
+#else
+ int fd_;
+#endif
+ size_t size_;
+ void *addr_;
+};
+
} // namespace detail
// ----------------------------------------------------------------------------
val = 0;
for (; cnt; i++, cnt--) {
if (!s[i]) { return false; }
- int v = 0;
+ auto v = 0;
if (is_hex(s[i], v)) {
val = val * 16 + v;
} else {
}
inline std::string from_i_to_hex(size_t n) {
- const char *charset = "0123456789abcdef";
+ static const auto charset = "0123456789abcdef";
std::string ret;
do {
ret = charset[n & 15] + ret;
inline size_t to_utf8(int code, char *buff) {
if (code < 0x0080) {
- buff[0] = (code & 0x7F);
+ buff[0] = static_cast<char>(code & 0x7F);
return 1;
} else if (code < 0x0800) {
buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
std::string out;
out.reserve(in.size());
- int val = 0;
- int valb = -6;
+ auto val = 0;
+ auto valb = -6;
for (auto c : in) {
val = (val << 8) + static_cast<uint8_t>(c);
// Read component
auto beg = i;
while (i < path.size() && path[i] != '/') {
+ if (path[i] == '\0') {
+ return false;
+ } else if (path[i] == '\\') {
+ return false;
+ }
i++;
}
for (size_t i = 0; i < s.size(); i++) {
if (s[i] == '%' && i + 1 < s.size()) {
if (s[i + 1] == 'u') {
- int val = 0;
+ auto val = 0;
if (from_hex_to_i(s, i + 2, 4, val)) {
// 4 digits Unicode codes
char buff[4];
result += s[i];
}
} else {
- int val = 0;
+ auto val = 0;
if (from_hex_to_i(s, i + 1, 2, val)) {
// 2 digits hex codes
result += static_cast<char>(val);
return s.substr(r.first, r.second - r.first);
}
+inline std::string trim_double_quotes_copy(const std::string &s) {
+ if (s.length() >= 2 && s.front() == '"' && s.back() == '"') {
+ return s.substr(1, s.size() - 2);
+ }
+ return s;
+}
+
inline void split(const char *b, const char *e, char d,
std::function<void(const char *, const char *)> fn) {
+ return split(b, e, d, (std::numeric_limits<size_t>::max)(), std::move(fn));
+}
+
+inline void split(const char *b, const char *e, char d, size_t m,
+ std::function<void(const char *, const char *)> fn) {
size_t i = 0;
size_t beg = 0;
+ size_t count = 1;
while (e ? (b + i < e) : (b[i] != '\0')) {
- if (b[i] == d) {
+ if (b[i] == d && count < m) {
auto r = trim(b, e, beg, i);
if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
beg = i + 1;
+ count++;
}
i++;
}
}
}
+inline mmap::mmap(const char *path)
+#if defined(_WIN32)
+ : hFile_(NULL), hMapping_(NULL)
+#else
+ : fd_(-1)
+#endif
+ ,
+ size_(0), addr_(nullptr) {
+ open(path);
+}
+
+inline mmap::~mmap() { close(); }
+
+inline bool mmap::open(const char *path) {
+ close();
+
+#if defined(_WIN32)
+ std::wstring wpath;
+ for (size_t i = 0; i < strlen(path); i++) {
+ wpath += path[i];
+ }
+
+ hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
+ OPEN_EXISTING, NULL);
+
+ if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
+
+ LARGE_INTEGER size{};
+ if (!::GetFileSizeEx(hFile_, &size)) { return false; }
+ size_ = static_cast<size_t>(size.QuadPart);
+
+ hMapping_ =
+ ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
+
+ if (hMapping_ == NULL) {
+ close();
+ return false;
+ }
+
+ addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
+#else
+ fd_ = ::open(path, O_RDONLY);
+ if (fd_ == -1) { return false; }
+
+ struct stat sb;
+ if (fstat(fd_, &sb) == -1) {
+ close();
+ return false;
+ }
+ size_ = static_cast<size_t>(sb.st_size);
+
+ addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
+#endif
+
+ if (addr_ == nullptr) {
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+inline bool mmap::is_open() const { return addr_ != nullptr; }
+
+inline size_t mmap::size() const { return size_; }
+
+inline const char *mmap::data() const {
+ return static_cast<const char *>(addr_);
+}
+
+inline void mmap::close() {
+#if defined(_WIN32)
+ if (addr_) {
+ ::UnmapViewOfFile(addr_);
+ addr_ = nullptr;
+ }
+
+ if (hMapping_) {
+ ::CloseHandle(hMapping_);
+ hMapping_ = NULL;
+ }
+
+ if (hFile_ != INVALID_HANDLE_VALUE) {
+ ::CloseHandle(hFile_);
+ hFile_ = INVALID_HANDLE_VALUE;
+ }
+#else
+ if (addr_ != nullptr) {
+ munmap(addr_, size_);
+ addr_ = nullptr;
+ }
+
+ if (fd_ != -1) {
+ ::close(fd_);
+ fd_ = -1;
+ }
+#endif
+ size_ = 0;
+}
inline int close_socket(socket_t sock) {
#ifdef _WIN32
return closesocket(sock);
}
template <typename T> inline ssize_t handle_EINTR(T fn) {
- ssize_t res = false;
+ ssize_t res = 0;
while (true) {
res = fn();
if (res < 0 && errno == EINTR) { continue; }
return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
#else
#ifndef _WIN32
- if (sock >= FD_SETSIZE) { return 1; }
+ if (sock >= FD_SETSIZE) { return -1; }
#endif
fd_set fds;
return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
#else
#ifndef _WIN32
- if (sock >= FD_SETSIZE) { return 1; }
+ if (sock >= FD_SETSIZE) { return -1; }
#endif
fd_set fds;
if (poll_res == 0) { return Error::ConnectionTimeout; }
if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
- int error = 0;
+ auto error = 0;
socklen_t len = sizeof(error);
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *>(&error), &len);
if (ret == 0) { return Error::ConnectionTimeout; }
if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
- int error = 0;
+ auto error = 0;
socklen_t len = sizeof(error);
auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *>(&error), &len);
return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0;
}
-class SocketStream : public Stream {
+class SocketStream final : public Stream {
public:
SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
time_t write_timeout_sec, time_t write_timeout_usec);
size_t read_buff_off_ = 0;
size_t read_buff_content_size_ = 0;
- static const size_t read_buff_size_ = 1024 * 4;
+ static const size_t read_buff_size_ = 1024l * 4;
};
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
-class SSLSocketStream : public Stream {
+class SSLSocketStream final : public Stream {
public:
SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec,
time_t read_timeout_usec, time_t write_timeout_sec,
#ifndef _WIN32
if (hints.ai_family == AF_UNIX) {
const auto addrlen = host.length();
- if (addrlen > sizeof(sockaddr_un::sun_path)) return INVALID_SOCKET;
+ if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; }
auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
if (sock != INVALID_SOCKET) {
#endif
if (tcp_nodelay) {
- int yes = 1;
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&yes),
- sizeof(yes));
+ auto yes = 1;
+#ifdef _WIN32
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ reinterpret_cast<const char *>(&yes), sizeof(yes));
+#else
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+ reinterpret_cast<const void *>(&yes), sizeof(yes));
+#endif
}
if (socket_options) { socket_options(sock); }
if (rp->ai_family == AF_INET6) {
- int no = 0;
- setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no),
- sizeof(no));
+ auto no = 0;
+#ifdef _WIN32
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ reinterpret_cast<const char *>(&no), sizeof(no));
+#else
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ reinterpret_cast<const void *>(&no), sizeof(no));
+#endif
}
// bind or connect
return ret;
}
-#if !defined _WIN32 && !defined ANDROID && !defined _AIX
+#if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__
#define USE_IF2IP
#endif
#ifdef USE_IF2IP
auto ip_from_if = if2ip(address_family, intf);
if (ip_from_if.empty()) { ip_from_if = intf; }
- if (!bind_ip_address(sock2, ip_from_if.c_str())) {
+ if (!bind_ip_address(sock2, ip_from_if)) {
error = Error::BindIPAddress;
return false;
}
#ifdef _WIN32
auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 +
read_timeout_usec / 1000);
- setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
- sizeof(timeout));
+ setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO,
+ reinterpret_cast<const char *>(&timeout), sizeof(timeout));
#else
timeval tv;
tv.tv_sec = static_cast<long>(read_timeout_sec);
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
- setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
+ setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO,
+ reinterpret_cast<const void *>(&tv), sizeof(tv));
#endif
}
{
#ifdef _WIN32
auto timeout = static_cast<uint32_t>(write_timeout_sec * 1000 +
write_timeout_usec / 1000);
- setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
- sizeof(timeout));
+ setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO,
+ reinterpret_cast<const char *>(&timeout), sizeof(timeout));
#else
timeval tv;
tv.tv_sec = static_cast<long>(write_timeout_sec);
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
- setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
+ setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO,
+ reinterpret_cast<const void *>(&tv), sizeof(tv));
#endif
}
} // namespace udl
-inline const char *
+inline std::string
find_content_type(const std::string &path,
- const std::map<std::string, std::string> &user_data) {
+ const std::map<std::string, std::string> &user_data,
+ const std::string &default_content_type) {
auto ext = file_extension(path);
auto it = user_data.find(ext);
- if (it != user_data.end()) { return it->second.c_str(); }
+ if (it != user_data.end()) { return it->second; }
using udl::operator""_t;
switch (str2tag(ext)) {
- default: return nullptr;
+ default: return default_content_type;
+
case "css"_t: return "text/css";
case "csv"_t: return "text/csv";
case "htm"_t:
}
}
-inline const char *status_message(int status) {
- switch (status) {
- case 100: return "Continue";
- case 101: return "Switching Protocol";
- case 102: return "Processing";
- case 103: return "Early Hints";
- case 200: return "OK";
- case 201: return "Created";
- case 202: return "Accepted";
- case 203: return "Non-Authoritative Information";
- case 204: return "No Content";
- case 205: return "Reset Content";
- case 206: return "Partial Content";
- case 207: return "Multi-Status";
- case 208: return "Already Reported";
- case 226: return "IM Used";
- case 300: return "Multiple Choice";
- case 301: return "Moved Permanently";
- case 302: return "Found";
- case 303: return "See Other";
- case 304: return "Not Modified";
- case 305: return "Use Proxy";
- case 306: return "unused";
- case 307: return "Temporary Redirect";
- case 308: return "Permanent Redirect";
- case 400: return "Bad Request";
- case 401: return "Unauthorized";
- case 402: return "Payment Required";
- case 403: return "Forbidden";
- case 404: return "Not Found";
- case 405: return "Method Not Allowed";
- case 406: return "Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Timeout";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Payload Too Large";
- case 414: return "URI Too Long";
- case 415: return "Unsupported Media Type";
- case 416: return "Range Not Satisfiable";
- case 417: return "Expectation Failed";
- case 418: return "I'm a teapot";
- case 421: return "Misdirected Request";
- case 422: return "Unprocessable Entity";
- case 423: return "Locked";
- case 424: return "Failed Dependency";
- case 425: return "Too Early";
- case 426: return "Upgrade Required";
- case 428: return "Precondition Required";
- case 429: return "Too Many Requests";
- case 431: return "Request Header Fields Too Large";
- case 451: return "Unavailable For Legal Reasons";
- case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Timeout";
- case 505: return "HTTP Version Not Supported";
- case 506: return "Variant Also Negotiates";
- case 507: return "Insufficient Storage";
- case 508: return "Loop Detected";
- case 510: return "Not Extended";
- case 511: return "Network Authentication Required";
-
- default:
- case 500: return "Internal Server Error";
- }
-}
-
inline bool can_compress_content_type(const std::string &content_type) {
using udl::operator""_t;
data += strm_.avail_in;
auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
- int ret = Z_OK;
+ auto ret = Z_OK;
std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
do {
Callback callback) {
assert(is_valid_);
- int ret = Z_OK;
+ auto ret = Z_OK;
do {
constexpr size_t max_avail_in =
data += strm_.avail_in;
std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
- while (strm_.avail_in > 0) {
+ while (strm_.avail_in > 0 && ret == Z_OK) {
strm_.avail_out = static_cast<uInt>(buff.size());
strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
- auto prev_avail_in = strm_.avail_in;
-
ret = inflate(&strm_, Z_NO_FLUSH);
- if (prev_avail_in - strm_.avail_in == 0) { return false; }
-
assert(ret != Z_STREAM_ERROR);
switch (ret) {
case Z_NEED_DICT:
}
}
- if (ret != Z_OK && ret != Z_STREAM_END) return false;
+ if (ret != Z_OK && ret != Z_STREAM_END) { return false; }
} while (data_length > 0);
return 0;
}
- const uint8_t *next_in = (const uint8_t *)data;
+ auto next_in = reinterpret_cast<const uint8_t *>(data);
size_t avail_in = data_length;
size_t total_out;
}
if (p < end) {
+ auto key_len = key_end - beg;
+ if (!key_len) { return false; }
+
auto key = std::string(beg, key_end);
auto val = compare_case_ignore(key, "Location")
? std::string(p, end)
uint64_t r = 0;
for (;;) {
auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ);
- if (n < 0) {
- return false;
- } else if (n == 0) {
- return true;
- }
+ if (n <= 0) { return true; }
if (!out(buf, static_cast<size_t>(n), r, 0)) { return false; }
r += static_cast<uint64_t>(n);
if (!line_reader.getline()) { return false; }
- if (strcmp(line_reader.ptr(), "\r\n")) { return false; }
+ if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; }
if (!line_reader.getline()) { return false; }
}
// Trailer
if (!line_reader.getline()) { return false; }
- while (strcmp(line_reader.ptr(), "\r\n")) {
+ while (strcmp(line_reader.ptr(), "\r\n") != 0) {
if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
// Exclude line terminator
}
inline bool is_chunked_transfer_encoding(const Headers &headers) {
- return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""),
- "chunked");
+ return compare_case_ignore(
+ get_header_value(headers, "Transfer-Encoding", 0, ""), "chunked");
}
template <typename T, typename U>
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
decompressor = detail::make_unique<gzip_decompressor>();
#else
- status = 415;
+ status = StatusCode::UnsupportedMediaType_415;
return false;
#endif
} else if (encoding.find("br") != std::string::npos) {
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
decompressor = detail::make_unique<brotli_decompressor>();
#else
- status = 415;
+ status = StatusCode::UnsupportedMediaType_415;
return false;
#endif
}
};
return callback(std::move(out));
} else {
- status = 500;
+ status = StatusCode::InternalServerError_500;
return false;
}
}
} else if (!has_header(x.headers, "Content-Length")) {
ret = read_content_without_length(strm, out);
} else {
- auto len = get_header_value<uint64_t>(x.headers, "Content-Length");
+ auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0);
if (len > payload_max_length) {
exceed_payload_max_length = true;
skip_content_with_length(strm, len);
}
}
- if (!ret) { status = exceed_payload_max_length ? 413 : 400; }
+ if (!ret) {
+ status = exceed_payload_max_length ? StatusCode::PayloadTooLarge_413
+ : StatusCode::BadRequest_400;
+ }
return ret;
});
} // namespace detail
return ok;
};
+ data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
+
while (offset < end_offset && !is_shutting_down()) {
if (!strm.is_writable()) {
error = Error::Write;
return ok;
};
+ data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
+
data_sink.done = [&](void) { data_available = false; };
while (data_available && !is_shutting_down()) {
return ok;
};
+ data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
+
auto done_with_trailer = [&](const Headers *trailer) {
if (!ok) { return; }
new_req.path = path;
new_req.redirect_count_ -= 1;
- if (res.status == 303 && (req.method != "GET" && req.method != "HEAD")) {
+ if (res.status == StatusCode::SeeOther_303 &&
+ (req.method != "GET" && req.method != "HEAD")) {
new_req.method = "GET";
new_req.body.clear();
new_req.headers.clear();
if (ret) {
req = new_req;
res = new_res;
- res.location = location;
+
+ if (res.location.empty()) { res.location = location; }
}
return ret;
}
if (pos == std::string::npos) { return false; }
auto end = content_type.find(';', pos);
auto beg = pos + strlen(boundary_keyword);
- boundary = content_type.substr(beg, end - beg);
- if (boundary.length() >= 2 && boundary.front() == '"' &&
- boundary.back() == '"') {
- boundary = boundary.substr(1, boundary.size() - 2);
- }
+ boundary = trim_double_quotes_copy(content_type.substr(beg, end - beg));
return !boundary.empty();
}
+inline void parse_disposition_params(const std::string &s, Params ¶ms) {
+ std::set<std::string> cache;
+ split(s.data(), s.data() + s.size(), ';', [&](const char *b, const char *e) {
+ std::string kv(b, e);
+ if (cache.find(kv) != cache.end()) { return; }
+ cache.insert(kv);
+
+ std::string key;
+ std::string val;
+ split(b, e, '=', [&](const char *b2, const char *e2) {
+ if (key.empty()) {
+ key.assign(b2, e2);
+ } else {
+ val.assign(b2, e2);
+ }
+ });
+
+ if (!key.empty()) {
+ params.emplace(trim_double_quotes_copy((key)),
+ trim_double_quotes_copy((val)));
+ }
+ });
+}
+
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
inline bool parse_range_header(const std::string &s, Ranges &ranges) {
#else
if (std::regex_match(s, m, re_first_range)) {
auto pos = static_cast<size_t>(m.position(1));
auto len = static_cast<size_t>(m.length(1));
- bool all_valid_ranges = true;
+ auto all_valid_ranges = true;
split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
- if (!all_valid_ranges) return;
+ if (!all_valid_ranges) { return; }
static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))");
std::cmatch cm;
if (std::regex_match(b, e, cm, re_another_range)) {
bool parse(const char *buf, size_t n, const ContentReceiver &content_callback,
const MultipartContentHeader &header_callback) {
- // TODO: support 'filename*'
- static const std::regex re_content_disposition(
- R"~(^Content-Disposition:\s*form-data;\s*name="(.*?)"(?:;\s*filename="(.*?)")?(?:;\s*filename\*=\S+)?\s*$)~",
- std::regex_constants::icase);
-
buf_append(buf, n);
while (buf_size() > 0) {
break;
}
- static const std::string header_name = "content-type:";
const auto header = buf_head(pos);
- if (start_with_case_ignore(header, header_name)) {
- file_.content_type = trim_copy(header.substr(header_name.size()));
+
+ if (!parse_header(header.data(), header.data() + header.size(),
+ [&](std::string &&, std::string &&) {})) {
+ is_valid_ = false;
+ return false;
+ }
+
+ static const std::string header_content_type = "Content-Type:";
+
+ if (start_with_case_ignore(header, header_content_type)) {
+ file_.content_type =
+ trim_copy(header.substr(header_content_type.size()));
} else {
+ static const std::regex re_content_disposition(
+ R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
+ std::regex_constants::icase);
+
std::smatch m;
if (std::regex_match(header, m, re_content_disposition)) {
- file_.name = m[1];
- file_.filename = m[2];
- } else {
- is_valid_ = false;
- return false;
+ Params params;
+ parse_disposition_params(m[1], params);
+
+ auto it = params.find("name");
+ if (it != params.end()) {
+ file_.name = it->second;
+ } else {
+ is_valid_ = false;
+ return false;
+ }
+
+ it = params.find("filename");
+ if (it != params.end()) { file_.filename = it->second; }
+
+ it = params.find("filename*");
+ if (it != params.end()) {
+ // Only allow UTF-8 enconnding...
+ static const std::regex re_rfc5987_encoding(
+ R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
+
+ std::smatch m2;
+ if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
+ file_.filename = decode_url(m2[1], false); // override...
+ } else {
+ is_valid_ = false;
+ return false;
+ }
+ }
}
}
buf_erase(pos + crlf_.size());
buf_erase(crlf_.size());
state_ = 1;
} else {
- if (dash_crlf_.size() > buf_size()) { return true; }
- if (buf_start_with(dash_crlf_)) {
- buf_erase(dash_crlf_.size());
+ if (dash_.size() > buf_size()) { return true; }
+ if (buf_start_with(dash_)) {
+ buf_erase(dash_.size());
is_valid_ = true;
buf_erase(buf_size()); // Remove epilogue
} else {
const std::string dash_ = "--";
const std::string crlf_ = "\r\n";
- const std::string dash_crlf_ = "--\r\n";
std::string boundary_;
std::string dash_boundary_crlf_;
std::string crlf_dash_boundary_;
return out;
}
-inline std::string make_multipart_data_boundary() {
+inline std::string random_string(size_t length) {
static const char data[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
// std::random_device might actually be deterministic on some
// platforms, but due to lack of support in the c++ standard library,
// doing better requires either some ugly hacks or breaking portability.
- std::random_device seed_gen;
+ static std::random_device seed_gen;
// Request 128 bits of entropy for initialization
- std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()};
- std::mt19937 engine(seed_sequence);
+ static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(),
+ seed_gen()};
- std::string result = "--cpp-httplib-multipart-data-";
+ static std::mt19937 engine(seed_sequence);
- for (auto i = 0; i < 16; i++) {
+ std::string result;
+ for (size_t i = 0; i < length; i++) {
result += data[engine() % (sizeof(data) - 1)];
}
-
return result;
}
+inline std::string make_multipart_data_boundary() {
+ return "--cpp-httplib-multipart-data-" + detail::random_string(16);
+}
+
inline bool is_multipart_boundary_chars_valid(const std::string &boundary) {
auto valid = true;
for (size_t i = 0; i < boundary.size(); i++) {
body += item.content + serialize_multipart_formdata_item_end();
}
- if (finish) body += serialize_multipart_formdata_finish(boundary);
+ if (finish) { body += serialize_multipart_formdata_finish(boundary); }
return body;
}
-inline std::pair<size_t, size_t>
-get_range_offset_and_length(const Request &req, size_t content_length,
- size_t index) {
- auto r = req.ranges[index];
+inline bool range_error(Request &req, Response &res) {
+ if (!req.ranges.empty() && 200 <= res.status && res.status < 300) {
+ ssize_t contant_len = static_cast<ssize_t>(
+ res.content_length_ ? res.content_length_ : res.body.size());
- if (r.first == -1 && r.second == -1) {
- return std::make_pair(0, content_length);
- }
+ ssize_t prev_first_pos = -1;
+ ssize_t prev_last_pos = -1;
+ size_t overwrapping_count = 0;
- auto slen = static_cast<ssize_t>(content_length);
+ // NOTE: The following Range check is based on '14.2. Range' in RFC 9110
+ // 'HTTP Semantics' to avoid potential denial-of-service attacks.
+ // https://www.rfc-editor.org/rfc/rfc9110#section-14.2
- if (r.first == -1) {
- r.first = (std::max)(static_cast<ssize_t>(0), slen - r.second);
- r.second = slen - 1;
+ // Too many ranges
+ if (req.ranges.size() > CPPHTTPLIB_RANGE_MAX_COUNT) { return true; }
+
+ for (auto &r : req.ranges) {
+ auto &first_pos = r.first;
+ auto &last_pos = r.second;
+
+ if (first_pos == -1 && last_pos == -1) {
+ first_pos = 0;
+ last_pos = contant_len;
+ }
+
+ if (first_pos == -1) {
+ first_pos = contant_len - last_pos;
+ last_pos = contant_len - 1;
+ }
+
+ if (last_pos == -1) { last_pos = contant_len - 1; }
+
+ // Range must be within content length
+ if (!(0 <= first_pos && first_pos <= last_pos &&
+ last_pos <= contant_len - 1)) {
+ return true;
+ }
+
+ // Ranges must be in ascending order
+ if (first_pos <= prev_first_pos) { return true; }
+
+ // Request must not have more than two overlapping ranges
+ if (first_pos <= prev_last_pos) {
+ overwrapping_count++;
+ if (overwrapping_count > 2) { return true; }
+ }
+
+ prev_first_pos = (std::max)(prev_first_pos, first_pos);
+ prev_last_pos = (std::max)(prev_last_pos, last_pos);
+ }
}
- if (r.second == -1) { r.second = slen - 1; }
+ return false;
+}
+
+inline std::pair<size_t, size_t>
+get_range_offset_and_length(Range r, size_t content_length) {
+ (void)(content_length); // patch to get rid of "unused parameter" on release build
+ assert(r.first != -1 && r.second != -1);
+ assert(0 <= r.first && r.first < static_cast<ssize_t>(content_length));
+ assert(r.first <= r.second &&
+ r.second < static_cast<ssize_t>(content_length));
+
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
}
-inline std::string make_content_range_header_field(size_t offset, size_t length,
- size_t content_length) {
+inline std::string make_content_range_header_field(
+ const std::pair<size_t, size_t> &offset_and_length, size_t content_length) {
+ auto st = offset_and_length.first;
+ auto ed = st + offset_and_length.second - 1;
+
std::string field = "bytes ";
- field += std::to_string(offset);
+ field += std::to_string(st);
field += "-";
- field += std::to_string(offset + length - 1);
+ field += std::to_string(ed);
field += "/";
field += std::to_string(content_length);
return field;
}
template <typename SToken, typename CToken, typename Content>
-bool process_multipart_ranges_data(const Request &req, Response &res,
+bool process_multipart_ranges_data(const Request &req,
const std::string &boundary,
const std::string &content_type,
- SToken stoken, CToken ctoken,
- Content content) {
+ size_t content_length, SToken stoken,
+ CToken ctoken, Content content) {
for (size_t i = 0; i < req.ranges.size(); i++) {
ctoken("--");
stoken(boundary);
ctoken("\r\n");
}
- auto offsets = get_range_offset_and_length(req, res.body.size(), i);
- auto offset = offsets.first;
- auto length = offsets.second;
+ auto offset_and_length =
+ get_range_offset_and_length(req.ranges[i], content_length);
ctoken("Content-Range: ");
- stoken(make_content_range_header_field(offset, length, res.body.size()));
+ stoken(make_content_range_header_field(offset_and_length, content_length));
ctoken("\r\n");
ctoken("\r\n");
- if (!content(offset, length)) { return false; }
+
+ if (!content(offset_and_length.first, offset_and_length.second)) {
+ return false;
+ }
ctoken("\r\n");
}
ctoken("--");
stoken(boundary);
- ctoken("--\r\n");
+ ctoken("--");
return true;
}
-inline bool make_multipart_ranges_data(const Request &req, Response &res,
+inline void make_multipart_ranges_data(const Request &req, Response &res,
const std::string &boundary,
const std::string &content_type,
+ size_t content_length,
std::string &data) {
- return process_multipart_ranges_data(
- req, res, boundary, content_type,
+ process_multipart_ranges_data(
+ req, boundary, content_type, content_length,
[&](const std::string &token) { data += token; },
[&](const std::string &token) { data += token; },
[&](size_t offset, size_t length) {
- if (offset < res.body.size()) {
- data += res.body.substr(offset, length);
- return true;
- }
- return false;
+ assert(offset + length <= content_length);
+ data += res.body.substr(offset, length);
+ return true;
});
}
-inline size_t
-get_multipart_ranges_data_length(const Request &req, Response &res,
- const std::string &boundary,
- const std::string &content_type) {
+inline size_t get_multipart_ranges_data_length(const Request &req,
+ const std::string &boundary,
+ const std::string &content_type,
+ size_t content_length) {
size_t data_length = 0;
process_multipart_ranges_data(
- req, res, boundary, content_type,
+ req, boundary, content_type, content_length,
[&](const std::string &token) { data_length += token.size(); },
[&](const std::string &token) { data_length += token.size(); },
[&](size_t /*offset*/, size_t length) {
}
template <typename T>
-inline bool write_multipart_ranges_data(Stream &strm, const Request &req,
- Response &res,
- const std::string &boundary,
- const std::string &content_type,
- const T &is_shutting_down) {
+inline bool
+write_multipart_ranges_data(Stream &strm, const Request &req, Response &res,
+ const std::string &boundary,
+ const std::string &content_type,
+ size_t content_length, const T &is_shutting_down) {
return process_multipart_ranges_data(
- req, res, boundary, content_type,
+ req, boundary, content_type, content_length,
[&](const std::string &token) { strm.write(token); },
[&](const std::string &token) { strm.write(token); },
[&](size_t offset, size_t length) {
});
}
-inline std::pair<size_t, size_t>
-get_range_offset_and_length(const Request &req, const Response &res,
- size_t index) {
- auto r = req.ranges[index];
-
- if (r.second == -1) {
- r.second = static_cast<ssize_t>(res.content_length_) - 1;
- }
-
- return std::make_pair(r.first, r.second - r.first + 1);
-}
-
inline bool expect_content(const Request &req) {
if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
req.method == "PRI" || req.method == "DELETE") {
std::stringstream ss;
for (auto i = 0u; i < hash_length; ++i) {
ss << std::hex << std::setw(2) << std::setfill('0')
- << (unsigned int)hash[i];
+ << static_cast<unsigned int>(hash[i]);
}
return ss.str();
inline bool add_certs_to_x509_store(CFArrayRef certs, X509_STORE *store) {
auto result = false;
- for (int i = 0; i < CFArrayGetCount(certs); ++i) {
+ for (auto i = 0; i < CFArrayGetCount(certs); ++i) {
const auto cert = reinterpret_cast<const __SecCertificate *>(
CFArrayGetValueAtIndex(certs, i));
s = s.substr(pos + 1);
auto beg = std::sregex_iterator(s.begin(), s.end(), re);
for (auto i = beg; i != std::sregex_iterator(); ++i) {
- auto m = *i;
+ const auto &m = *i;
auto key = s.substr(static_cast<size_t>(m.position(1)),
static_cast<size_t>(m.length(1)));
auto val = m.length(2) > 0
return false;
}
-// https://stackoverflow.com/questions/440133/how-do-i-create-a-random-alpha-numeric-string-in-c/440240#answer-440240
-inline std::string random_string(size_t length) {
- auto randchar = []() -> char {
- const char charset[] = "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz";
- const size_t max_index = (sizeof(charset) - 1);
- return charset[static_cast<size_t>(std::rand()) % max_index];
- };
- std::string str(length, 0);
- std::generate_n(str.begin(), length, randchar);
- return str;
-}
-
class ContentProviderAdapter {
public:
explicit ContentProviderAdapter(
const auto &addr =
*reinterpret_cast<struct sockaddr_storage *>(rp->ai_addr);
std::string ip;
- int dummy = -1;
+ auto dummy = -1;
if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage), ip,
dummy)) {
addrs.push_back(ip);
}
// Header utilities
-inline std::pair<std::string, std::string> make_range_header(Ranges ranges) {
+inline std::pair<std::string, std::string>
+make_range_header(const Ranges &ranges) {
std::string field = "bytes=";
auto i = 0;
- for (auto r : ranges) {
+ for (const auto &r : ranges) {
if (i != 0) { field += ", "; }
if (r.first != -1) { field += std::to_string(r.first); }
field += '-';
if (300 <= stat && stat < 400) {
this->status = stat;
} else {
- this->status = 302;
+ this->status = StatusCode::Found_302;
}
}
}
set_content(s.data(), s.size(), content_type);
}
+inline void Response::set_content(std::string &&s,
+ const std::string &content_type) {
+ body = std::move(s);
+
+ auto rng = headers.equal_range("Content-Type");
+ headers.erase(rng.first, rng.second);
+ set_header("Content-Type", content_type);
+}
+
inline void Response::set_content_provider(
size_t in_length, const std::string &content_type, ContentProvider provider,
ContentProviderResourceReleaser resource_releaser) {
set_header("Content-Type", content_type);
content_length_ = in_length;
if (in_length > 0) { content_provider_ = std::move(provider); }
- content_provider_resource_releaser_ = resource_releaser;
+ content_provider_resource_releaser_ = std::move(resource_releaser);
is_chunked_content_provider_ = false;
}
set_header("Content-Type", content_type);
content_length_ = 0;
content_provider_ = detail::ContentProviderAdapter(std::move(provider));
- content_provider_resource_releaser_ = resource_releaser;
+ content_provider_resource_releaser_ = std::move(resource_releaser);
is_chunked_content_provider_ = false;
}
set_header("Content-Type", content_type);
content_length_ = 0;
content_provider_ = detail::ContentProviderAdapter(std::move(provider));
- content_provider_resource_releaser_ = resource_releaser;
+ content_provider_resource_releaser_ = std::move(resource_releaser);
is_chunked_content_provider_ = true;
}
write_timeout_sec_(write_timeout_sec),
write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}
-inline SocketStream::~SocketStream() {}
+inline SocketStream::~SocketStream() = default;
inline bool SocketStream::is_readable() const {
return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
inline const std::string &BufferStream::get_buffer() const { return buffer; }
+inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) {
+ // One past the last ending position of a path param substring
+ std::size_t last_param_end = 0;
+
+#ifndef CPPHTTPLIB_NO_EXCEPTIONS
+ // Needed to ensure that parameter names are unique during matcher
+ // construction
+ // If exceptions are disabled, only last duplicate path
+ // parameter will be set
+ std::unordered_set<std::string> param_name_set;
+#endif
+
+ while (true) {
+ const auto marker_pos = pattern.find(marker, last_param_end);
+ if (marker_pos == std::string::npos) { break; }
+
+ static_fragments_.push_back(
+ pattern.substr(last_param_end, marker_pos - last_param_end));
+
+ const auto param_name_start = marker_pos + 1;
+
+ auto sep_pos = pattern.find(separator, param_name_start);
+ if (sep_pos == std::string::npos) { sep_pos = pattern.length(); }
+
+ auto param_name =
+ pattern.substr(param_name_start, sep_pos - param_name_start);
+
+#ifndef CPPHTTPLIB_NO_EXCEPTIONS
+ if (param_name_set.find(param_name) != param_name_set.cend()) {
+ std::string msg = "Encountered path parameter '" + param_name +
+ "' multiple times in route pattern '" + pattern + "'.";
+ throw std::invalid_argument(msg);
+ }
+#endif
+
+ param_names_.push_back(std::move(param_name));
+
+ last_param_end = sep_pos + 1;
+ }
+
+ if (last_param_end < pattern.length()) {
+ static_fragments_.push_back(pattern.substr(last_param_end));
+ }
+}
+
+inline bool PathParamsMatcher::match(Request &request) const {
+ request.matches = std::smatch();
+ request.path_params.clear();
+ request.path_params.reserve(param_names_.size());
+
+ // One past the position at which the path matched the pattern last time
+ std::size_t starting_pos = 0;
+ for (size_t i = 0; i < static_fragments_.size(); ++i) {
+ const auto &fragment = static_fragments_[i];
+
+ if (starting_pos + fragment.length() > request.path.length()) {
+ return false;
+ }
+
+ // Avoid unnecessary allocation by using strncmp instead of substr +
+ // comparison
+ if (std::strncmp(request.path.c_str() + starting_pos, fragment.c_str(),
+ fragment.length()) != 0) {
+ return false;
+ }
+
+ starting_pos += fragment.length();
+
+ // Should only happen when we have a static fragment after a param
+ // Example: '/users/:id/subscriptions'
+ // The 'subscriptions' fragment here does not have a corresponding param
+ if (i >= param_names_.size()) { continue; }
+
+ auto sep_pos = request.path.find(separator, starting_pos);
+ if (sep_pos == std::string::npos) { sep_pos = request.path.length(); }
+
+ const auto ¶m_name = param_names_[i];
+
+ request.path_params.emplace(
+ param_name, request.path.substr(starting_pos, sep_pos - starting_pos));
+
+ // Mark everythin up to '/' as matched
+ starting_pos = sep_pos + 1;
+ }
+ // Returns false if the path is longer than the pattern
+ return starting_pos >= request.path.length();
+}
+
+inline bool RegexMatcher::match(Request &request) const {
+ request.path_params.clear();
+ return std::regex_match(request.path, request.matches, regex_);
+}
+
} // namespace detail
// HTTP server implementation
#endif
}
-inline Server::~Server() {}
+inline Server::~Server() = default;
+
+inline std::unique_ptr<detail::MatcherBase>
+Server::make_matcher(const std::string &pattern) {
+ if (pattern.find("/:") != std::string::npos) {
+ return detail::make_unique<detail::PathParamsMatcher>(pattern);
+ } else {
+ return detail::make_unique<detail::RegexMatcher>(pattern);
+ }
+}
inline Server &Server::Get(const std::string &pattern, Handler handler) {
- get_handlers_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ get_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
return *this;
}
inline Server &Server::Post(const std::string &pattern, Handler handler) {
- post_handlers_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ post_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
return *this;
}
inline Server &Server::Post(const std::string &pattern,
HandlerWithContentReader handler) {
- post_handlers_for_content_reader_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ post_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
+ std::move(handler));
return *this;
}
inline Server &Server::Put(const std::string &pattern, Handler handler) {
- put_handlers_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ put_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
return *this;
}
inline Server &Server::Put(const std::string &pattern,
HandlerWithContentReader handler) {
- put_handlers_for_content_reader_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ put_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
+ std::move(handler));
return *this;
}
inline Server &Server::Patch(const std::string &pattern, Handler handler) {
- patch_handlers_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
return *this;
}
inline Server &Server::Patch(const std::string &pattern,
HandlerWithContentReader handler) {
- patch_handlers_for_content_reader_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
+ std::move(handler));
return *this;
}
inline Server &Server::Delete(const std::string &pattern, Handler handler) {
- delete_handlers_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
return *this;
}
inline Server &Server::Delete(const std::string &pattern,
HandlerWithContentReader handler) {
- delete_handlers_for_content_reader_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
+ std::move(handler));
return *this;
}
inline Server &Server::Options(const std::string &pattern, Handler handler) {
- options_handlers_.push_back(
- std::make_pair(std::regex(pattern), std::move(handler)));
+ options_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
return *this;
}
return *this;
}
+inline Server &Server::set_default_file_mimetype(const std::string &mime) {
+ default_file_mimetype_ = mime;
+ return *this;
+}
+
inline Server &Server::set_file_request_handler(Handler handler) {
file_request_handler_ = std::move(handler);
return *this;
inline Server &
Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
expect_100_continue_handler_ = std::move(handler);
-
return *this;
}
return *this;
}
+inline Server &Server::set_header_writer(
+ std::function<ssize_t(Stream &, Headers &)> const &writer) {
+ header_writer_ = writer;
+ return *this;
+}
+
inline Server &Server::set_keep_alive_max_count(size_t count) {
keep_alive_max_count_ = count;
return *this;
inline bool Server::bind_to_port(const std::string &host, int port,
int socket_flags) {
- if (bind_internal(host, port, socket_flags) < 0) return false;
- return true;
+ return bind_internal(host, port, socket_flags) >= 0;
}
inline int Server::bind_to_any_port(const std::string &host, int socket_flags) {
return bind_internal(host, 0, socket_flags);
}
}
-inline bool Server::parse_request_line(const char *s, Request &req) {
+inline bool Server::parse_request_line(const char *s, Request &req) const {
auto len = strlen(s);
if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
len -= 2;
size_t count = 0;
detail::split(req.target.data(), req.target.data() + req.target.size(), '?',
- [&](const char *b, const char *e) {
+ 2, [&](const char *b, const char *e) {
switch (count) {
case 0:
req.path = detail::decode_url(std::string(b, e), false);
}
inline bool Server::write_response(Stream &strm, bool close_connection,
- const Request &req, Response &res) {
+ Request &req, Response &res) {
+ // NOTE: `req.ranges` should be empty, otherwise it will be applied
+ // incorrectly to the error content.
+ req.ranges.clear();
return write_response_core(strm, close_connection, req, res, false);
}
detail::BufferStream bstrm;
if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status,
- detail::status_message(res.status))) {
+ status_message(res.status))) {
return false;
}
- if (!detail::write_headers(bstrm, res.headers)) { return false; }
+ if (!header_writer_(bstrm, res.headers)) { return false; }
// Flush buffer
auto &data = bstrm.get_buffer();
if (write_content_with_provider(strm, req, res, boundary, content_type)) {
res.content_provider_success_ = true;
} else {
- res.content_provider_success_ = false;
ret = false;
}
}
return detail::write_content(strm, res.content_provider_, 0,
res.content_length_, is_shutting_down);
} else if (req.ranges.size() == 1) {
- auto offsets =
- detail::get_range_offset_and_length(req, res.content_length_, 0);
- auto offset = offsets.first;
- auto length = offsets.second;
- return detail::write_content(strm, res.content_provider_, offset, length,
- is_shutting_down);
+ auto offset_and_length = detail::get_range_offset_and_length(
+ req.ranges[0], res.content_length_);
+
+ return detail::write_content(strm, res.content_provider_,
+ offset_and_length.first,
+ offset_and_length.second, is_shutting_down);
} else {
return detail::write_multipart_ranges_data(
- strm, req, res, boundary, content_type, is_shutting_down);
+ strm, req, res, boundary, content_type, res.content_length_,
+ is_shutting_down);
}
} else {
if (res.is_chunked_content_provider_) {
const auto &content_type = req.get_header_value("Content-Type");
if (!content_type.find("application/x-www-form-urlencoded")) {
if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) {
- res.status = 413; // NOTE: should be 414?
+ res.status = StatusCode::PayloadTooLarge_413; // NOTE: should be 414?
return false;
}
detail::parse_query_text(req.body, req.params);
std::move(multipart_receiver));
}
-inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
- ContentReceiver receiver,
- MultipartContentHeader multipart_header,
- ContentReceiver multipart_receiver) {
+inline bool
+Server::read_content_core(Stream &strm, Request &req, Response &res,
+ ContentReceiver receiver,
+ MultipartContentHeader multipart_header,
+ ContentReceiver multipart_receiver) const {
detail::MultipartFormDataParser multipart_form_data_parser;
ContentReceiverWithProgress out;
const auto &content_type = req.get_header_value("Content-Type");
std::string boundary;
if (!detail::parse_multipart_boundary(content_type, boundary)) {
- res.status = 400;
+ res.status = StatusCode::BadRequest_400;
return false;
}
if (req.is_multipart_form_data()) {
if (!multipart_form_data_parser.is_valid()) {
- res.status = 400;
+ res.status = StatusCode::BadRequest_400;
return false;
}
}
if (path.back() == '/') { path += "index.html"; }
if (detail::is_file(path)) {
- detail::read_file(path, res.body);
- auto type =
- detail::find_content_type(path, file_extension_and_mimetype_map_);
- if (type) { res.set_header("Content-Type", type); }
for (const auto &kv : entry.headers) {
- res.set_header(kv.first.c_str(), kv.second);
+ res.set_header(kv.first, kv.second);
}
- res.status = req.has_header("Range") ? 206 : 200;
+
+ auto mm = std::make_shared<detail::mmap>(path.c_str());
+ if (!mm->is_open()) { return false; }
+
+ res.set_content_provider(
+ mm->size(),
+ detail::find_content_type(path, file_extension_and_mimetype_map_,
+ default_file_mimetype_),
+ [mm](size_t offset, size_t length, DataSink &sink) -> bool {
+ sink.write(mm->data() + offset, length);
+ return true;
+ });
+
if (!head && file_request_handler_) {
file_request_handler_(req, res);
}
+
return true;
}
}
#ifdef _WIN32
auto timeout = static_cast<uint32_t>(read_timeout_sec_ * 1000 +
read_timeout_usec_ / 1000);
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
- sizeof(timeout));
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+ reinterpret_cast<const char *>(&timeout), sizeof(timeout));
#else
timeval tv;
tv.tv_sec = static_cast<long>(read_timeout_sec_);
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec_);
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+ reinterpret_cast<const void *>(&tv), sizeof(tv));
#endif
}
{
#ifdef _WIN32
auto timeout = static_cast<uint32_t>(write_timeout_sec_ * 1000 +
write_timeout_usec_ / 1000);
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
- sizeof(timeout));
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+ reinterpret_cast<const char *>(&timeout), sizeof(timeout));
#else
timeval tv;
tv.tv_sec = static_cast<long>(write_timeout_sec_);
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec_);
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+ reinterpret_cast<const void *>(&tv), sizeof(tv));
#endif
}
- task_queue->enqueue([this, sock]() { process_and_close_socket(sock); });
+ if (!task_queue->enqueue(
+ [this, sock]() { process_and_close_socket(sock); })) {
+ detail::shutdown_socket(sock);
+ detail::close_socket(sock);
+ }
}
task_queue->shutdown();
}
// File handler
- bool is_head_request = req.method == "HEAD";
+ auto is_head_request = req.method == "HEAD";
if ((req.method == "GET" || is_head_request) &&
handle_file_request(req, res, is_head_request)) {
return true;
return dispatch_request(req, res, patch_handlers_);
}
- res.status = 400;
+ res.status = StatusCode::BadRequest_400;
return false;
}
inline bool Server::dispatch_request(Request &req, Response &res,
- const Handlers &handlers) {
+ const Handlers &handlers) const {
for (const auto &x : handlers) {
- const auto &pattern = x.first;
+ const auto &matcher = x.first;
const auto &handler = x.second;
- if (std::regex_match(req.path, req.matches, pattern)) {
+ if (matcher->match(req)) {
handler(req, res);
return true;
}
inline void Server::apply_ranges(const Request &req, Response &res,
std::string &content_type,
- std::string &boundary) {
+ std::string &boundary) const {
if (req.ranges.size() > 1) {
- boundary = detail::make_multipart_data_boundary();
-
auto it = res.headers.find("Content-Type");
if (it != res.headers.end()) {
content_type = it->second;
res.headers.erase(it);
}
- res.headers.emplace("Content-Type",
- "multipart/byteranges; boundary=" + boundary);
+ boundary = detail::make_multipart_data_boundary();
+
+ res.set_header("Content-Type",
+ "multipart/byteranges; boundary=" + boundary);
}
auto type = detail::encoding_type(req, res);
if (req.ranges.empty()) {
length = res.content_length_;
} else if (req.ranges.size() == 1) {
- auto offsets =
- detail::get_range_offset_and_length(req, res.content_length_, 0);
- auto offset = offsets.first;
- length = offsets.second;
+ auto offset_and_length = detail::get_range_offset_and_length(
+ req.ranges[0], res.content_length_);
+
+ length = offset_and_length.second;
+
auto content_range = detail::make_content_range_header_field(
- offset, length, res.content_length_);
+ offset_and_length, res.content_length_);
res.set_header("Content-Range", content_range);
} else {
- length = detail::get_multipart_ranges_data_length(req, res, boundary,
- content_type);
+ length = detail::get_multipart_ranges_data_length(
+ req, boundary, content_type, res.content_length_);
}
res.set_header("Content-Length", std::to_string(length));
} else {
if (req.ranges.empty()) {
;
} else if (req.ranges.size() == 1) {
- auto offsets =
- detail::get_range_offset_and_length(req, res.body.size(), 0);
- auto offset = offsets.first;
- auto length = offsets.second;
+ auto offset_and_length =
+ detail::get_range_offset_and_length(req.ranges[0], res.body.size());
+ auto offset = offset_and_length.first;
+ auto length = offset_and_length.second;
+
auto content_range = detail::make_content_range_header_field(
- offset, length, res.body.size());
+ offset_and_length, res.body.size());
res.set_header("Content-Range", content_range);
- if (offset < res.body.size()) {
- res.body = res.body.substr(offset, length);
- } else {
- res.body.clear();
- res.status = 416;
- }
+
+ assert(offset + length <= res.body.size());
+ res.body = res.body.substr(offset, length);
} else {
std::string data;
- if (detail::make_multipart_ranges_data(req, res, boundary, content_type,
- data)) {
- res.body.swap(data);
- } else {
- res.body.clear();
- res.status = 416;
- }
+ detail::make_multipart_ranges_data(req, res, boundary, content_type,
+ res.body.size(), data);
+ res.body.swap(data);
}
if (type != detail::EncodingType::None) {
inline bool Server::dispatch_request_for_content_reader(
Request &req, Response &res, ContentReader content_reader,
- const HandlersForContentReader &handlers) {
+ const HandlersForContentReader &handlers) const {
for (const auto &x : handlers) {
- const auto &pattern = x.first;
+ const auto &matcher = x.first;
const auto &handler = x.second;
- if (std::regex_match(req.path, req.matches, pattern)) {
+ if (matcher->match(req)) {
handler(req, res, content_reader);
return true;
}
if (!line_reader.getline()) { return false; }
Request req;
- Response res;
+ Response res;
res.version = "HTTP/1.1";
-
- for (const auto &header : default_headers_) {
- if (res.headers.find(header.first) == res.headers.end()) {
- res.headers.insert(header);
- }
- }
+ res.headers = default_headers_;
#ifdef _WIN32
// TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL).
if (strm.socket() >= FD_SETSIZE) {
Headers dummy;
detail::read_headers(strm, dummy);
- res.status = 500;
+ res.status = StatusCode::InternalServerError_500;
return write_response(strm, close_connection, req, res);
}
#endif
if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
Headers dummy;
detail::read_headers(strm, dummy);
- res.status = 414;
+ res.status = StatusCode::UriTooLong_414;
return write_response(strm, close_connection, req, res);
}
// Request line and headers
if (!parse_request_line(line_reader.ptr(), req) ||
!detail::read_headers(strm, req.headers)) {
- res.status = 400;
+ res.status = StatusCode::BadRequest_400;
return write_response(strm, close_connection, req, res);
}
if (req.has_header("Range")) {
const auto &range_header_value = req.get_header_value("Range");
if (!detail::parse_range_header(range_header_value, req.ranges)) {
- res.status = 416;
+ res.status = StatusCode::RangeNotSatisfiable_416;
return write_response(strm, close_connection, req, res);
}
}
if (setup_request) { setup_request(req); }
if (req.get_header_value("Expect") == "100-continue") {
- auto status = 100;
+ int status = StatusCode::Continue_100;
if (expect_100_continue_handler_) {
status = expect_100_continue_handler_(req, res);
}
switch (status) {
- case 100:
- case 417:
+ case StatusCode::Continue_100:
+ case StatusCode::ExpectationFailed_417:
strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status,
- detail::status_message(status));
+ status_message(status));
break;
default: return write_response(strm, close_connection, req, res);
}
}
- // Rounting
- bool routed = false;
+ // Routing
+ auto routed = false;
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
routed = routing(req, res, strm);
#else
exception_handler_(req, res, ep);
routed = true;
} else {
- res.status = 500;
+ res.status = StatusCode::InternalServerError_500;
std::string val;
auto s = e.what();
for (size_t i = 0; s[i]; i++) {
exception_handler_(req, res, ep);
routed = true;
} else {
- res.status = 500;
+ res.status = StatusCode::InternalServerError_500;
res.set_header("EXCEPTION_WHAT", "UNKNOWN");
}
}
#endif
-
if (routed) {
- if (res.status == -1) { res.status = req.ranges.empty() ? 200 : 206; }
+ if (res.status == -1) {
+ res.status = req.ranges.empty() ? StatusCode::OK_200
+ : StatusCode::PartialContent_206;
+ }
+
+ if (detail::range_error(req, res)) {
+ res.body.clear();
+ res.content_length_ = 0;
+ res.content_provider_ = nullptr;
+ res.status = StatusCode::RangeNotSatisfiable_416;
+ return write_response(strm, close_connection, req, res);
+ }
+
return write_response_with_content(strm, close_connection, req, res);
} else {
- if (res.status == -1) { res.status = 404; }
+ if (res.status == -1) { res.status = StatusCode::NotFound_404; }
+
return write_response(strm, close_connection, req, res);
}
}
// Check is custom IP specified for host_
std::string ip;
auto it = addr_map_.find(host_);
- if (it != addr_map_.end()) ip = it->second;
+ if (it != addr_map_.end()) { ip = it->second; }
return detail::create_client_socket(
host_, ip, port_, address_family_, tcp_nodelay_, socket_options_,
socket_requests_are_from_thread_ == std::this_thread::get_id());
}
-inline void ClientImpl::shutdown_socket(Socket &socket) {
+inline void ClientImpl::shutdown_socket(Socket &socket) const {
if (socket.sock == INVALID_SOCKET) { return; }
detail::shutdown_socket(socket.sock);
}
}
inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
- Response &res) {
+ Response &res) const {
std::array<char, 2048> buf{};
detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
if (!line_reader.getline()) { return false; }
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
- const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
-#else
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
+#else
+ const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
#endif
std::cmatch m;
res.reason = std::string(m[3]);
// Ignore '100 Continue'
- while (res.status == 100) {
+ while (res.status == StatusCode::Continue_100) {
if (!line_reader.getline()) { return false; } // CRLF
if (!line_reader.getline()) { return false; } // next response line
if (!ret) { return false; }
+ if (res.get_header_value("Connection") == "close" ||
+ (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
+ // TODO this requires a not-entirely-obvious chain of calls to be correct
+ // for this to be safe.
+
+ // This is safe to call because handle_request is only called by send_
+ // which locks the request mutex during the process. It would be a bug
+ // to call it from a different thread since it's a thread-safety issue
+ // to do these things to the socket if another thread is using the socket.
+ std::lock_guard<std::mutex> guard(socket_mutex_);
+ shutdown_ssl(socket_, true);
+ shutdown_socket(socket_);
+ close_socket(socket_);
+ }
+
if (300 < res.status && res.status < 400 && follow_location_) {
req = req_save;
ret = redirect(req, res, error);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- if ((res.status == 401 || res.status == 407) &&
+ if ((res.status == StatusCode::Unauthorized_401 ||
+ res.status == StatusCode::ProxyAuthenticationRequired_407) &&
req.authorization_count_ < 5) {
- auto is_proxy = res.status == 407;
+ auto is_proxy = res.status == StatusCode::ProxyAuthenticationRequired_407;
const auto &username =
is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
const auto &password =
} else {
if (next_scheme == "https") {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
- SSLClient cli(next_host.c_str(), next_port);
+ SSLClient cli(next_host, next_port);
cli.copy_settings(*this);
if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
return detail::redirect(cli, req, res, path, location, error);
return false;
#endif
} else {
- ClientImpl cli(next_host.c_str(), next_port);
+ ClientImpl cli(next_host, next_port);
cli.copy_settings(*this);
return detail::redirect(cli, req, res, path, location, error);
}
inline bool ClientImpl::write_content_with_provider(Stream &strm,
const Request &req,
- Error &error) {
+ Error &error) const {
auto is_shutting_down = []() { return false; };
if (req.is_chunked_content_provider_) {
// Prepare additional headers
if (close_connection) {
if (!req.has_header("Connection")) {
- req.headers.emplace("Connection", "close");
+ req.set_header("Connection", "close");
}
}
if (!req.has_header("Host")) {
if (is_ssl()) {
if (port_ == 443) {
- req.headers.emplace("Host", host_);
+ req.set_header("Host", host_);
} else {
- req.headers.emplace("Host", host_and_port_);
+ req.set_header("Host", host_and_port_);
}
} else {
if (port_ == 80) {
- req.headers.emplace("Host", host_);
+ req.set_header("Host", host_);
} else {
- req.headers.emplace("Host", host_and_port_);
+ req.set_header("Host", host_and_port_);
}
}
}
- if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); }
+ if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
if (!req.has_header("User-Agent")) {
auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
- req.headers.emplace("User-Agent", agent);
+ req.set_header("User-Agent", agent);
}
#endif
if (!req.is_chunked_content_provider_) {
if (!req.has_header("Content-Length")) {
auto length = std::to_string(req.content_length_);
- req.headers.emplace("Content-Length", length);
+ req.set_header("Content-Length", length);
}
}
} else {
if (req.method == "POST" || req.method == "PUT" ||
req.method == "PATCH") {
- req.headers.emplace("Content-Length", "0");
+ req.set_header("Content-Length", "0");
}
}
} else {
if (!req.has_header("Content-Type")) {
- req.headers.emplace("Content-Type", "text/plain");
+ req.set_header("Content-Type", "text/plain");
}
if (!req.has_header("Content-Length")) {
auto length = std::to_string(req.body.size());
- req.headers.emplace("Content-Length", length);
+ req.set_header("Content-Length", length);
}
}
const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path;
bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
- detail::write_headers(bstrm, req.headers);
+ header_writer_(bstrm, req.headers);
// Flush buffer
auto &data = bstrm.get_buffer();
ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const std::string &content_type, Error &error) {
- if (!content_type.empty()) {
- req.headers.emplace("Content-Type", content_type);
- }
+ if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
- if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
+ if (compress_) { req.set_header("Content-Encoding", "gzip"); }
#endif
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
req.content_provider_ = detail::ContentProviderAdapter(
std::move(content_provider_without_length));
req.is_chunked_content_provider_ = true;
- req.headers.emplace("Transfer-Encoding", "chunked");
+ req.set_header("Transfer-Encoding", "chunked");
} else {
req.body.assign(body, content_length);
- ;
}
}
}
// Body
- if ((res.status != 204) && req.method != "HEAD" && req.method != "CONNECT") {
+ if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" &&
+ req.method != "CONNECT") {
auto redirect = 300 < res.status && res.status < 400 && follow_location_;
if (req.response_handler && !redirect) {
}
}
- if (res.get_header_value("Connection") == "close" ||
- (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
- // TODO this requires a not-entirely-obvious chain of calls to be correct
- // for this to be safe. Maybe a code refactor (such as moving this out to
- // the send function and getting rid of the recursiveness of the mutex)
- // could make this more obvious.
-
- // This is safe to call because process_request is only called by
- // handle_request which is only called by send, which locks the request
- // mutex during the process. It would be a bug to call it from a different
- // thread since it's a thread-safety issue to do these things to the socket
- // if another thread is using the socket.
- std::lock_guard<std::mutex> guard(socket_mutex_);
- shutdown_ssl(socket_, true);
- shutdown_socket(socket_);
- close_socket(socket_);
- }
-
// Log
if (logger_) { logger_(req, res); }
inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
const std::string &boundary, const MultipartFormDataItems &items,
- const MultipartFormDataProviderItems &provider_items) {
- size_t cur_item = 0, cur_start = 0;
+ const MultipartFormDataProviderItems &provider_items) const {
+ size_t cur_item = 0;
+ size_t cur_start = 0;
// cur_item and cur_start are copied to within the std::function and maintain
// state between successive calls
return [&, cur_item, cur_start](size_t offset,
DataSink &sink) mutable -> bool {
- if (!offset && items.size()) {
+ if (!offset && !items.empty()) {
sink.os << detail::serialize_multipart_formdata(items, boundary, false);
return true;
} else if (cur_item < provider_items.size()) {
}
DataSink cur_sink;
- bool has_data = true;
+ auto has_data = true;
cur_sink.write = sink.write;
cur_sink.done = [&]() { has_data = false; };
- if (!provider_items[cur_item].provider(offset - cur_start, cur_sink))
+ if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) {
return false;
+ }
if (!has_data) {
sink.os << detail::serialize_multipart_formdata_item_end();
if (params.empty()) { return Get(path, headers); }
std::string path_with_query = append_query_params(path, params);
- return Get(path_with_query.c_str(), headers, progress);
+ return Get(path_with_query, headers, std::move(progress));
}
inline Result ClientImpl::Get(const std::string &path, const Params ¶ms,
const Headers &headers,
ContentReceiver content_receiver,
Progress progress) {
- return Get(path, params, headers, nullptr, content_receiver, progress);
+ return Get(path, params, headers, nullptr, std::move(content_receiver),
+ std::move(progress));
}
inline Result ClientImpl::Get(const std::string &path, const Params ¶ms,
ContentReceiver content_receiver,
Progress progress) {
if (params.empty()) {
- return Get(path, headers, response_handler, content_receiver, progress);
+ return Get(path, headers, std::move(response_handler),
+ std::move(content_receiver), std::move(progress));
}
std::string path_with_query = append_query_params(path, params);
- return Get(path_with_query.c_str(), headers, response_handler,
- content_receiver, progress);
+ return Get(path_with_query, headers, std::move(response_handler),
+ std::move(content_receiver), std::move(progress));
}
inline Result ClientImpl::Head(const std::string &path) {
const auto &content_type =
detail::serialize_multipart_formdata_get_content_type(boundary);
const auto &body = detail::serialize_multipart_formdata(items, boundary);
- return Post(path, headers, body, content_type.c_str());
+ return Post(path, headers, body, content_type);
}
inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
const auto &content_type =
detail::serialize_multipart_formdata_get_content_type(boundary);
const auto &body = detail::serialize_multipart_formdata(items, boundary);
- return Post(path, headers, body, content_type.c_str());
+ return Post(path, headers, body, content_type);
}
inline Result
req.headers = headers;
req.path = path;
- if (!content_type.empty()) {
- req.headers.emplace("Content-Type", content_type);
- }
+ if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
req.body.assign(body, content_length);
return send_(std::move(req));
return send_(std::move(req));
}
-inline size_t ClientImpl::is_socket_open() const {
- std::lock_guard<std::mutex> guard(socket_mutex_);
- return socket_.is_open();
-}
-
-inline socket_t ClientImpl::socket() const { return socket_.sock; }
-
inline void ClientImpl::stop() {
std::lock_guard<std::mutex> guard(socket_mutex_);
close_socket(socket_);
}
+inline std::string ClientImpl::host() const { return host_; }
+
+inline int ClientImpl::port() const { return port_; }
+
+inline size_t ClientImpl::is_socket_open() const {
+ std::lock_guard<std::mutex> guard(socket_mutex_);
+ return socket_.is_open();
+}
+
+inline socket_t ClientImpl::socket() const { return socket_.sock; }
+
inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
connection_timeout_sec_ = sec;
connection_timeout_usec_ = usec;
default_headers_ = std::move(headers);
}
+inline void ClientImpl::set_header_writer(
+ std::function<ssize_t(Stream &, Headers &)> const &writer) {
+ header_writer_ = writer;
+}
+
inline void ClientImpl::set_address_family(int family) {
address_family_ = family;
}
proxy_digest_auth_username_ = username;
proxy_digest_auth_password_ = password;
}
-#endif
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path,
const std::string &ca_cert_dir_path) {
ca_cert_file_path_ = ca_cert_file_path;
ca_cert_store_ = ca_cert_store;
}
}
-#endif
-#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
+ std::size_t size) const {
+ auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
+ if (!mem) { return nullptr; }
+
+ auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
+ if (!inf) {
+ BIO_free_all(mem);
+ return nullptr;
+ }
+
+ auto cts = X509_STORE_new();
+ if (cts) {
+ for (auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) {
+ auto itmp = sk_X509_INFO_value(inf, i);
+ if (!itmp) { continue; }
+
+ if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
+ if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
+ }
+ }
+
+ sk_X509_INFO_pop_free(inf, X509_INFO_free);
+ BIO_free_all(mem);
+ return cts;
+}
+
inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
server_certificate_verification_ = enabled;
}
U ssl_connect_or_accept,
time_t timeout_sec,
time_t timeout_usec) {
- int res = 0;
+ auto res = 0;
while ((res = ssl_connect_or_accept(ssl)) != 1) {
auto err = SSL_get_error(ssl, res);
switch (err) {
SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
}
-inline SSLSocketStream::~SSLSocketStream() {}
+inline SSLSocketStream::~SSLSocketStream() = default;
inline bool SSLSocketStream::is_readable() const {
return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
if (ret < 0) {
auto err = SSL_get_error(ssl_, ret);
- int n = 1000;
+ auto n = 1000;
#ifdef _WIN32
while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
(err == SSL_ERROR_SYSCALL &&
auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
if (ret < 0) {
auto err = SSL_get_error(ssl_, ret);
- int n = 1000;
+ auto n = 1000;
#ifdef _WIN32
while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
(err == SSL_ERROR_SYSCALL &&
SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);
- // add default password callback before opening encrypted private key
if (private_key_password != nullptr && (private_key_password[0] != '\0')) {
- SSL_CTX_set_default_passwd_cb_userdata(ctx_,
- (char *)private_key_password);
+ SSL_CTX_set_default_passwd_cb_userdata(
+ ctx_,
+ reinterpret_cast<void *>(const_cast<char *>(private_key_password)));
}
if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
inline SSLClient::SSLClient(const std::string &host, int port,
const std::string &client_cert_path,
- const std::string &client_key_path)
+ const std::string &client_key_path,
+ const std::string &private_key_password)
: ClientImpl(host, port, client_cert_path, client_key_path) {
ctx_ = SSL_CTX_new(TLS_client_method());
detail::split(&host_[0], &host_[host_.size()], '.',
[&](const char *b, const char *e) {
- host_components_.emplace_back(std::string(b, e));
+ host_components_.emplace_back(b, e);
});
if (!client_cert_path.empty() && !client_key_path.empty()) {
+ if (!private_key_password.empty()) {
+ SSL_CTX_set_default_passwd_cb_userdata(
+ ctx_, reinterpret_cast<void *>(
+ const_cast<char *>(private_key_password.c_str())));
+ }
+
if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(),
SSL_FILETYPE_PEM) != 1 ||
SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(),
}
inline SSLClient::SSLClient(const std::string &host, int port,
- X509 *client_cert, EVP_PKEY *client_key)
+ X509 *client_cert, EVP_PKEY *client_key,
+ const std::string &private_key_password)
: ClientImpl(host, port) {
ctx_ = SSL_CTX_new(TLS_client_method());
detail::split(&host_[0], &host_[host_.size()], '.',
[&](const char *b, const char *e) {
- host_components_.emplace_back(std::string(b, e));
+ host_components_.emplace_back(b, e);
});
if (client_cert != nullptr && client_key != nullptr) {
+ if (!private_key_password.empty()) {
+ SSL_CTX_set_default_passwd_cb_userdata(
+ ctx_, reinterpret_cast<void *>(
+ const_cast<char *>(private_key_password.c_str())));
+ }
+
if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 ||
SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) {
SSL_CTX_free(ctx_);
}
}
+inline void SSLClient::load_ca_cert_store(const char *ca_cert,
+ std::size_t size) {
+ set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size));
+}
+
inline long SSLClient::get_openssl_verify_result() const {
return verify_result_;
}
inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
bool &success, Error &error) {
success = true;
- Response res2;
+ Response proxy_res;
if (!detail::process_client_socket(
socket.sock, read_timeout_sec_, read_timeout_usec_,
write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
Request req2;
req2.method = "CONNECT";
req2.path = host_and_port_;
- return process_request(strm, req2, res2, false, error);
+ return process_request(strm, req2, proxy_res, false, error);
})) {
// Thread-safe to close everything because we are assuming there are no
// requests in flight
return false;
}
- if (res2.status == 407) {
+ if (proxy_res.status == StatusCode::ProxyAuthenticationRequired_407) {
if (!proxy_digest_auth_username_.empty() &&
!proxy_digest_auth_password_.empty()) {
std::map<std::string, std::string> auth;
- if (detail::parse_www_authenticate(res2, auth, true)) {
- Response res3;
+ if (detail::parse_www_authenticate(proxy_res, auth, true)) {
+ proxy_res = Response();
if (!detail::process_client_socket(
socket.sock, read_timeout_sec_, read_timeout_usec_,
write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
req3, auth, 1, detail::random_string(10),
proxy_digest_auth_username_, proxy_digest_auth_password_,
true));
- return process_request(strm, req3, res3, false, error);
+ return process_request(strm, req3, proxy_res, false, error);
})) {
// Thread-safe to close everything because we are assuming there are
// no requests in flight
return false;
}
}
- } else {
- res = res2;
- return false;
}
}
+ // If status code is not 200, proxy request is failed.
+ // Set error to ProxyConnection and return proxy response
+ // as the response of the request
+ if (proxy_res.status != StatusCode::OK_200) {
+ error = Error::ProxyConnection;
+ res = std::move(proxy_res);
+ // Thread-safe to close everything because we are assuming there are
+ // no requests in flight
+ shutdown_ssl(socket, true);
+ shutdown_socket(socket);
+ close_socket(socket);
+ return false;
+ }
+
return true;
}
inline bool SSLClient::load_certs() {
- bool ret = true;
+ auto ret = true;
std::call_once(initialize_cert_, [&]() {
std::lock_guard<std::mutex> guard(ctx_mutex_);
return true;
},
[&](SSL *ssl2) {
- SSL_set_tlsext_host_name(ssl2, host_.c_str());
+ // NOTE: Direct call instead of using the OpenSSL macro to suppress
+ // -Wold-style-cast warning
+ // SSL_set_tlsext_host_name(ssl2, host_.c_str());
+ SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name,
+ static_cast<void *>(const_cast<char *>(host_.c_str())));
return true;
});
auto type = GEN_DNS;
- struct in6_addr addr6;
- struct in_addr addr;
+ struct in6_addr addr6 {};
+ struct in_addr addr {};
size_t addr_len = 0;
#ifndef __MINGW32__
for (decltype(count) i = 0; i < count && !dsn_matched; i++) {
auto val = sk_GENERAL_NAME_value(alt_names, i);
if (val->type == type) {
- auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5);
- auto name_len = (size_t)ASN1_STRING_length(val->d.ia5);
+ auto name =
+ reinterpret_cast<const char *>(ASN1_STRING_get0_data(val->d.ia5));
+ auto name_len = static_cast<size_t>(ASN1_STRING_length(val->d.ia5));
switch (type) {
case GEN_DNS: dsn_matched = check_host_name(name, name_len); break;
if (dsn_matched || ip_matched) { ret = true; }
}
- GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names);
+ GENERAL_NAMES_free(const_cast<STACK_OF(GENERAL_NAME) *>(
+ reinterpret_cast<const STACK_OF(GENERAL_NAME) *>(alt_names)));
return ret;
}
std::vector<std::string> pattern_components;
detail::split(&pattern[0], &pattern[pattern_len], '.',
[&](const char *b, const char *e) {
- pattern_components.emplace_back(std::string(b, e));
+ pattern_components.emplace_back(b, e);
});
if (host_components_.size() != pattern_components.size()) { return false; }
: cli_(detail::make_unique<ClientImpl>(host, port, client_cert_path,
client_key_path)) {}
-inline Client::~Client() {}
+inline Client::~Client() = default;
inline bool Client::is_valid() const {
return cli_ != nullptr && cli_->is_valid();
}
inline Result Client::Get(const std::string &path, const Params ¶ms,
const Headers &headers, Progress progress) {
- return cli_->Get(path, params, headers, progress);
+ return cli_->Get(path, params, headers, std::move(progress));
}
inline Result Client::Get(const std::string &path, const Params ¶ms,
const Headers &headers,
ContentReceiver content_receiver, Progress progress) {
- return cli_->Get(path, params, headers, content_receiver, progress);
+ return cli_->Get(path, params, headers, std::move(content_receiver),
+ std::move(progress));
}
inline Result Client::Get(const std::string &path, const Params ¶ms,
const Headers &headers,
ResponseHandler response_handler,
ContentReceiver content_receiver, Progress progress) {
- return cli_->Get(path, params, headers, response_handler, content_receiver,
- progress);
+ return cli_->Get(path, params, headers, std::move(response_handler),
+ std::move(content_receiver), std::move(progress));
}
inline Result Client::Head(const std::string &path) { return cli_->Head(path); }
inline Result Client::send(const Request &req) { return cli_->send(req); }
+inline void Client::stop() { cli_->stop(); }
+
+inline std::string Client::host() const { return cli_->host(); }
+
+inline int Client::port() const { return cli_->port(); }
+
inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
inline socket_t Client::socket() const { return cli_->socket(); }
-inline void Client::stop() { cli_->stop(); }
-
inline void
Client::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
cli_->set_hostname_addr_map(std::move(addr_map));
cli_->set_default_headers(std::move(headers));
}
+inline void Client::set_header_writer(
+ std::function<ssize_t(Stream &, Headers &)> const &writer) {
+ cli_->set_header_writer(writer);
+}
+
inline void Client::set_address_family(int family) {
cli_->set_address_family(family);
}
}
#endif
-inline void Client::set_logger(Logger logger) { cli_->set_logger(logger); }
+inline void Client::set_logger(Logger logger) {
+ cli_->set_logger(std::move(logger));
+}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path,
}
}
+inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) {
+ set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size));
+}
+
inline long Client::get_openssl_verify_result() const {
if (is_ssl_) {
return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
/****************************************************************************\
#endif // JSON_NO_IO
#include <iterator> // random_access_iterator_tag
#include <memory> // unique_ptr
-#include <numeric> // accumulate
#include <string> // string, stoi, to_string
#include <utility> // declval, forward, move, pair, swap
#include <vector> // vector
// #include <nlohmann/adl_serializer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/abi_macros.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
- #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2
+ #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
#warning "Already included a different version of the library!"
#endif
#endif
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
-#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum)
+#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
#ifndef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 0
// #include <nlohmann/detail/conversions/from_json.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/exceptions.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include <cstddef> // nullptr_t
#include <exception> // exception
+#if JSON_DIAGNOSTICS
+ #include <numeric> // accumulate
+#endif
#include <stdexcept> // runtime_error
#include <string> // to_string
#include <vector> // vector
// #include <nlohmann/detail/value_t.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/macro_scope.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/detected.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/void_t.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com>
// SPDX-License-Identifier: MIT
#endif
#endif
+#ifndef JSON_HAS_STATIC_RTTI
+ #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0
+ #define JSON_HAS_STATIC_RTTI 1
+ #else
+ #define JSON_HAS_STATIC_RTTI 0
+ #endif
+#endif
+
#ifdef JSON_HAS_CPP_17
#define JSON_INLINE_VARIABLE inline
#else
class NumberUnsignedType, class NumberFloatType, \
template<typename> class AllocatorType, \
template<typename, typename = void> class JSONSerializer, \
- class BinaryType>
+ class BinaryType, \
+ class CustomBaseClass>
#define NLOHMANN_BASIC_JSON_TPL \
basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
- AllocatorType, JSONSerializer, BinaryType>
+ AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>
// Macros to simplify conversion from/to types
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
- friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+ friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
+
+#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
+ friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
/*!
@brief macro
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
+#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
+ inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
+
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
- inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
-
+ inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
// inspired from https://stackoverflow.com/a/26745591
// allows to call any std function as if (e.g. with begin):
// #include <nlohmann/detail/string_escape.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/input/position_t.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/cpp_future.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2018 The Abseil Authors
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/type_traits.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <utility> // declval
#include <tuple> // tuple
+#include <string> // char_traits
// #include <nlohmann/detail/iterators/iterator_traits.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/call_std/begin.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/call_std/end.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/json_fwd.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer,
- class BinaryType = std::vector<std::uint8_t>>
+ class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
+ class CustomBaseClass = void>
class basic_json;
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
template<typename BasicJsonType>
using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
+/////////////////
+// char_traits //
+/////////////////
+
+// Primary template of char_traits calls std char_traits
+template<typename T>
+struct char_traits : std::char_traits<T>
+{};
+
+// Explicitly define char traits for unsigned char since it is not standard
+template<>
+struct char_traits<unsigned char> : std::char_traits<char>
+{
+ using char_type = unsigned char;
+ using int_type = uint64_t;
+
+ // Redefine to_int_type function
+ static int_type to_int_type(char_type c) noexcept
+ {
+ return static_cast<int_type>(c);
+ }
+
+ static char_type to_char_type(int_type i) noexcept
+ {
+ return static_cast<char_type>(i);
+ }
+
+ static constexpr int_type eof() noexcept
+ {
+ return static_cast<int_type>(EOF);
+ }
+};
+
+// Explicitly define char traits for signed char since it is not standard
+template<>
+struct char_traits<signed char> : std::char_traits<char>
+{
+ using char_type = signed char;
+ using int_type = uint64_t;
+
+ // Redefine to_int_type function
+ static int_type to_int_type(char_type c) noexcept
+ {
+ return static_cast<int_type>(c);
+ }
+
+ static char_type to_char_type(int_type i) noexcept
+ {
+ return static_cast<char_type>(i);
+ }
+
+ static constexpr int_type eof() noexcept
+ {
+ return static_cast<int_type>(EOF);
+ }
+};
+
///////////////////
// is_ functions //
///////////////////
struct is_default_constructible<const std::tuple<Ts...>>
: conjunction<is_default_constructible<Ts>...> {};
-
template <typename T, typename... Args>
struct is_constructible : std::is_constructible<T, Args...> {};
template <typename... Ts>
struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
-
template<typename T, typename = void>
struct is_iterator_traits : std::false_type {};
}
};
-
template<typename OfType, typename T>
struct value_in_range_of_impl2<OfType, T, true, true>
{
// #include <nlohmann/detail/string_concat.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
}
template<typename... Args>
-inline std::size_t concat_length(const char* cstr, Args&& ... rest);
+inline std::size_t concat_length(const char* cstr, const Args& ... rest);
template<typename StringType, typename... Args>
-inline std::size_t concat_length(const StringType& str, Args&& ... rest);
+inline std::size_t concat_length(const StringType& str, const Args& ... rest);
template<typename... Args>
-inline std::size_t concat_length(const char /*c*/, Args&& ... rest)
+inline std::size_t concat_length(const char /*c*/, const Args& ... rest)
{
- return 1 + concat_length(std::forward<Args>(rest)...);
+ return 1 + concat_length(rest...);
}
template<typename... Args>
-inline std::size_t concat_length(const char* cstr, Args&& ... rest)
+inline std::size_t concat_length(const char* cstr, const Args& ... rest)
{
// cppcheck-suppress ignoredReturnValue
- return ::strlen(cstr) + concat_length(std::forward<Args>(rest)...);
+ return ::strlen(cstr) + concat_length(rest...);
}
template<typename StringType, typename... Args>
-inline std::size_t concat_length(const StringType& str, Args&& ... rest)
+inline std::size_t concat_length(const StringType& str, const Args& ... rest)
{
- return str.size() + concat_length(std::forward<Args>(rest)...);
+ return str.size() + concat_length(rest...);
}
template<typename OutStringType>
inline OutStringType concat(Args && ... args)
{
OutStringType str;
- str.reserve(concat_length(std::forward<Args>(args)...));
+ str.reserve(concat_length(args...));
concat_into(str, std::forward<Args>(args)...);
return str;
}
NLOHMANN_JSON_NAMESPACE_END
-
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
{
{
case value_t::array:
{
- for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
+ for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)
{
- if (¤t->m_parent->m_value.array->operator[](i) == current)
+ if (¤t->m_parent->m_data.m_value.array->operator[](i) == current)
{
tokens.emplace_back(std::to_string(i));
break;
case value_t::object:
{
- for (const auto& element : *current->m_parent->m_value.object)
+ for (const auto& element : *current->m_parent->m_data.m_value.object)
{
if (&element.second == current)
{
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
{
- std::string w = concat(exception::name("parse_error", id_), "parse error",
- position_string(pos), ": ", exception::diagnostics(context), what_arg);
+ const std::string w = concat(exception::name("parse_error", id_), "parse error",
+ position_string(pos), ": ", exception::diagnostics(context), what_arg);
return {id_, pos.chars_read_total, w.c_str()};
}
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
{
- std::string w = concat(exception::name("parse_error", id_), "parse error",
- (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
- ": ", exception::diagnostics(context), what_arg);
+ const std::string w = concat(exception::name("parse_error", id_), "parse error",
+ (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
+ ": ", exception::diagnostics(context), what_arg);
return {id_, byte_, w.c_str()};
}
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
{
- std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
+ const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
return {id_, w.c_str()};
}
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
{
- std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
+ const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
return {id_, w.c_str()};
}
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
{
- std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
+ const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
return {id_, w.c_str()};
}
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
{
- std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
+ const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
return {id_, w.c_str()};
}
// #include <nlohmann/detail/meta/identity_tag.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/meta/std_fs.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/conversions/to_json.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
iteration_proxy_value(iteration_proxy_value&&)
noexcept(std::is_nothrow_move_constructible<IteratorType>::value
- && std::is_nothrow_move_constructible<string_type>::value) = default;
+ && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
iteration_proxy_value& operator=(iteration_proxy_value&&)
noexcept(std::is_nothrow_move_assignable<IteratorType>::value
- && std::is_nothrow_move_assignable<string_type>::value) = default;
+ && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
~iteration_proxy_value() = default;
/// dereference operator (needed for range-based for)
#pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
template<typename IteratorType>
-class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
+class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
: public std::integral_constant<std::size_t, 2> {};
template<std::size_t N, typename IteratorType>
-class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
+class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)
{
public:
using type = decltype(
/*
* Note all external_constructor<>::construct functions need to call
- * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an
+ * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
* allocated value (e.g., a string). See bug issue
* https://github.com/nlohmann/json/issues/2865 for more information.
*/
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::boolean;
- j.m_value = b;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::boolean;
+ j.m_data.m_value = b;
j.assert_invariant();
}
};
template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::string;
- j.m_value = s;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::string;
+ j.m_data.m_value = s;
j.assert_invariant();
}
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::string;
- j.m_value = std::move(s);
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::string;
+ j.m_data.m_value = std::move(s);
j.assert_invariant();
}
int > = 0 >
static void construct(BasicJsonType& j, const CompatibleStringType& str)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::string;
- j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::string;
+ j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
j.assert_invariant();
}
};
template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::binary;
- j.m_value = typename BasicJsonType::binary_t(b);
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::binary;
+ j.m_data.m_value = typename BasicJsonType::binary_t(b);
j.assert_invariant();
}
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::binary;
- j.m_value = typename BasicJsonType::binary_t(std::move(b));
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::binary;
+ j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
j.assert_invariant();
}
};
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::number_float;
- j.m_value = val;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::number_float;
+ j.m_data.m_value = val;
j.assert_invariant();
}
};
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::number_unsigned;
- j.m_value = val;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::number_unsigned;
+ j.m_data.m_value = val;
j.assert_invariant();
}
};
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::number_integer;
- j.m_value = val;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::number_integer;
+ j.m_data.m_value = val;
j.assert_invariant();
}
};
template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::array;
- j.m_value = arr;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::array;
+ j.m_data.m_value = arr;
j.set_parents();
j.assert_invariant();
}
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::array;
- j.m_value = std::move(arr);
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::array;
+ j.m_data.m_value = std::move(arr);
j.set_parents();
j.assert_invariant();
}
using std::begin;
using std::end;
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::array;
- j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::array;
+ j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
j.set_parents();
j.assert_invariant();
}
template<typename BasicJsonType>
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::array;
- j.m_value = value_t::array;
- j.m_value.array->reserve(arr.size());
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::array;
+ j.m_data.m_value = value_t::array;
+ j.m_data.m_value.array->reserve(arr.size());
for (const bool x : arr)
{
- j.m_value.array->push_back(x);
- j.set_parent(j.m_value.array->back());
+ j.m_data.m_value.array->push_back(x);
+ j.set_parent(j.m_data.m_value.array->back());
}
j.assert_invariant();
}
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::array;
- j.m_value = value_t::array;
- j.m_value.array->resize(arr.size());
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::array;
+ j.m_data.m_value = value_t::array;
+ j.m_data.m_value.array->resize(arr.size());
if (arr.size() > 0)
{
- std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
+ std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
}
j.set_parents();
j.assert_invariant();
template<typename BasicJsonType>
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::object;
- j.m_value = obj;
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::object;
+ j.m_data.m_value = obj;
j.set_parents();
j.assert_invariant();
}
template<typename BasicJsonType>
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
{
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::object;
- j.m_value = std::move(obj);
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::object;
+ j.m_data.m_value = std::move(obj);
j.set_parents();
j.assert_invariant();
}
using std::begin;
using std::end;
- j.m_value.destroy(j.m_type);
- j.m_type = value_t::object;
- j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
+ j.m_data.m_value.destroy(j.m_data.m_type);
+ j.m_data.m_type = value_t::object;
+ j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
j.set_parents();
j.assert_invariant();
}
inline void to_json(BasicJsonType& j, EnumType e) noexcept
{
using underlying_type = typename std::underlying_type<EnumType>::type;
- external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
+ static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;
+ external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e));
}
#endif // JSON_DISABLE_ENUM_SERIALIZATION
// #include <nlohmann/byte_container_with_subtype.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/hash.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/input/binary_reader.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/input/input_adapters.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/macro_scope.hpp>
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
std::FILE* m_file;
};
-
/*!
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
beginning of input. Does not support changing the underlying std::streambuf
: current(std::move(first)), end(std::move(last))
{}
- typename std::char_traits<char_type>::int_type get_character()
+ typename char_traits<char_type>::int_type get_character()
{
if (JSON_HEDLEY_LIKELY(current != end))
{
- auto result = std::char_traits<char_type>::to_int_type(*current);
+ auto result = char_traits<char_type>::to_int_type(*current);
std::advance(current, 1);
return result;
}
- return std::char_traits<char_type>::eof();
+ return char_traits<char_type>::eof();
}
private:
}
};
-
template<typename BaseInputAdapter, size_t T>
struct wide_string_input_helper;
}
};
-// Wraps another input apdater to convert wide character types into individual bytes.
+// Wraps another input adapter to convert wide character types into individual bytes.
template<typename BaseInputAdapter, typename WideCharType>
class wide_string_input_adapter
{
std::size_t utf8_bytes_filled = 0;
};
-
template<typename IteratorType, typename Enable = void>
struct iterator_input_adapter_factory
{
// #include <nlohmann/detail/input/json_sax.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
virtual ~json_sax() = default;
};
-
namespace detail
{
/*!
JSON_ASSERT(ref_stack.back()->is_object());
// add null at given key and store the reference for later
- object_element = &(ref_stack.back()->m_value.object->operator[](val));
+ object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));
return true;
}
if (ref_stack.back()->is_array())
{
- ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
- return &(ref_stack.back()->m_value.array->back());
+ ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
+ return &(ref_stack.back()->m_data.m_value.array->back());
}
JSON_ASSERT(ref_stack.back()->is_object());
// add discarded value at given key and store the reference for later
if (keep && ref_stack.back())
{
- object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
+ object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
}
return true;
// remove discarded value
if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
{
- ref_stack.back()->m_value.array->pop_back();
+ ref_stack.back()->m_data.m_value.array->pop_back();
}
return true;
if (ref_stack.empty())
{
root = std::move(value);
- return {true, &root};
+ return {true, & root};
}
// skip this value if we already decided to skip the parent
// array
if (ref_stack.back()->is_array())
{
- ref_stack.back()->m_value.array->emplace_back(std::move(value));
- return {true, &(ref_stack.back()->m_value.array->back())};
+ ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
+ return {true, & (ref_stack.back()->m_data.m_value.array->back())};
}
// object
/// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack {};
/// stack to manage which values to keep
- std::vector<bool> keep_stack {};
+ std::vector<bool> keep_stack {}; // NOLINT(readability-redundant-member-init)
/// stack to manage which object keys to keep
- std::vector<bool> key_keep_stack {};
+ std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init)
/// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred
// #include <nlohmann/detail/input/lexer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/macro_scope.hpp>
+// #include <nlohmann/detail/meta/type_traits.hpp>
+
NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using char_type = typename InputAdapterType::char_type;
- using char_int_type = typename std::char_traits<char_type>::int_type;
+ using char_int_type = typename char_traits<char_type>::int_type;
public:
using token_type = typename lexer_base<BasicJsonType>::token_type;
for (auto range = ranges.begin(); range != ranges.end(); ++range)
{
get();
- if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))
+ if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions)
{
add(current);
}
switch (get())
{
// end of file while parsing string
- case std::char_traits<char_type>::eof():
+ case char_traits<char_type>::eof():
{
error_message = "invalid string: missing closing quote";
return token_type::parse_error;
{
case '\n':
case '\r':
- case std::char_traits<char_type>::eof():
+ case char_traits<char_type>::eof():
case '\0':
return true;
{
switch (get())
{
- case std::char_traits<char_type>::eof():
+ case char_traits<char_type>::eof():
case '\0':
{
error_message = "invalid comment; missing closing '*/'";
token_type scan_literal(const char_type* literal_text, const std::size_t length,
token_type return_type)
{
- JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
+ JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]);
for (std::size_t i = 1; i < length; ++i)
{
- if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
+ if (JSON_HEDLEY_UNLIKELY(char_traits<char_type>::to_char_type(get()) != literal_text[i]))
{
error_message = "invalid literal";
return token_type::parse_error;
{
token_buffer.clear();
token_string.clear();
- token_string.push_back(std::char_traits<char_type>::to_char_type(current));
+ token_string.push_back(char_traits<char_type>::to_char_type(current));
}
/*
This function provides the interface to the used input adapter. It does
not throw in case the input reached EOF, but returns a
- `std::char_traits<char>::eof()` in that case. Stores the scanned characters
+ `char_traits<char>::eof()` in that case. Stores the scanned characters
for use in error messages.
@return character read from the input
current = ia.get_character();
}
- if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
+ if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))
{
- token_string.push_back(std::char_traits<char_type>::to_char_type(current));
+ token_string.push_back(char_traits<char_type>::to_char_type(current));
}
if (current == '\n')
--position.chars_read_current_line;
}
- if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
+ if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))
{
JSON_ASSERT(!token_string.empty());
token_string.pop_back();
// end of input (the null byte is needed when parsing from
// string literals)
case '\0':
- case std::char_traits<char_type>::eof():
+ case char_traits<char_type>::eof():
return token_type::end_of_input;
// error
const bool ignore_comments = false;
/// the current character
- char_int_type current = std::char_traits<char_type>::eof();
+ char_int_type current = char_traits<char_type>::eof();
/// whether the next get() call should just return current
bool next_unget = false;
// #include <nlohmann/detail/meta/is_sax.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
return *reinterpret_cast<char*>(&num) == 1;
}
-
///////////////////
// binary reader //
///////////////////
using binary_t = typename BasicJsonType::binary_t;
using json_sax_t = SAX;
using char_type = typename InputAdapterType::char_type;
- using char_int_type = typename std::char_traits<char_type>::int_type;
+ using char_int_type = typename char_traits<char_type>::int_type;
public:
/*!
get();
}
- if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
+ if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
}
- return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();
+ return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
}
/*!
{
std::array<char, 3> cr{{}};
static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
- std::string cr_str{cr.data()};
+ const std::string cr_str{cr.data()};
return sax->parse_error(element_type_parse_position, cr_str,
parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
}
switch (get_char ? get() : current)
{
// EOF
- case std::char_traits<char_type>::eof():
+ case char_traits<char_type>::eof():
return unexpect_eof(input_format_t::cbor, "value");
// Integer 0x00..0x17 (0..23)
switch (get())
{
// EOF
- case std::char_traits<char_type>::eof():
+ case char_traits<char_type>::eof():
return unexpect_eof(input_format_t::msgpack, "value");
// positive fixint
exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
}
- bool is_error = get_ubjson_size_value(result.first, is_ndarray);
+ const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray)
{
if (inside_ndarray)
if (current == '#')
{
- bool is_error = get_ubjson_size_value(result.first, is_ndarray);
+ const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray)
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
{
switch (prefix)
{
- case std::char_traits<char_type>::eof(): // EOF
+ case char_traits<char_type>::eof(): // EOF
return unexpect_eof(input_format, "value");
case 'T': // true
This function provides the interface to the used input adapter. It does
not throw in case the input reached EOF, but returns a -'ve valued
- `std::char_traits<char_type>::eof()` in that case.
+ `char_traits<char_type>::eof()` in that case.
@return character read from the input
*/
JSON_HEDLEY_NON_NULL(3)
bool unexpect_eof(const input_format_t format, const char* context) const
{
- if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
+ if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
{
return sax->parse_error(chars_read, "<end of file>",
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
InputAdapterType ia;
/// the current character
- char_int_type current = std::char_traits<char_type>::eof();
+ char_int_type current = char_traits<char_type>::eof();
/// the number of characters read
std::size_t chars_read = 0;
// #include <nlohmann/detail/input/parser.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
}
+ case token_type::end_of_input:
+ {
+ if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
+ {
+ return sax->parse_error(m_lexer.get_position(),
+ m_lexer.get_token_string(),
+ parse_error::create(101, m_lexer.get_position(),
+ "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
+ }
+ return sax->parse_error(m_lexer.get_position(),
+ m_lexer.get_token_string(),
+ parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
+ }
case token_type::uninitialized:
case token_type::end_array:
case token_type::end_object:
case token_type::name_separator:
case token_type::value_separator:
- case token_type::end_of_input:
case token_type::literal_or_value:
default: // the last token was unexpected
{
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/iterators/iter_impl.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
- m_it.object_iterator = m_object->m_value.object->begin();
+ m_it.object_iterator = m_object->m_data.m_value.object->begin();
break;
}
case value_t::array:
{
- m_it.array_iterator = m_object->m_value.array->begin();
+ m_it.array_iterator = m_object->m_data.m_value.array->begin();
break;
}
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
- m_it.object_iterator = m_object->m_value.object->end();
+ m_it.object_iterator = m_object->m_data.m_value.object->end();
break;
}
case value_t::array:
{
- m_it.array_iterator = m_object->m_value.array->end();
+ m_it.array_iterator = m_object->m_data.m_value.array->end();
break;
}
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
- JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
+ JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
return m_it.object_iterator->second;
}
case value_t::array:
{
- JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
+ JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return *m_it.array_iterator;
}
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
- JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
+ JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
return &(m_it.object_iterator->second);
}
case value_t::array:
{
- JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
+ JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return &*m_it.array_iterator;
}
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
return (m_it.object_iterator == other.m_it.object_iterator);
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
{
JSON_ASSERT(m_object != nullptr);
- switch (m_object->m_type)
+ switch (m_object->m_data.m_type)
{
case value_t::object:
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
+// #include <nlohmann/detail/json_custom_base_class.hpp>
+// __ _____ _____ _____
+// __| | __| | | | JSON for Modern C++
+// | | |__ | | | | | | version 3.11.3
+// |_____|_____|_____|_|___| https://github.com/nlohmann/json
+//
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
+// SPDX-License-Identifier: MIT
+
+
+
+#include <type_traits> // conditional, is_same
+
+// #include <nlohmann/detail/abi_macros.hpp>
+
+
+NLOHMANN_JSON_NAMESPACE_BEGIN
+namespace detail
+{
+
+/*!
+@brief Default base class of the @ref basic_json class.
+
+So that the correct implementations of the copy / move ctors / assign operators
+of @ref basic_json do not require complex case distinctions
+(no base class / custom base class used as customization point),
+@ref basic_json always has a base class.
+By default, this class is used because it is empty and thus has no effect
+on the behavior of @ref basic_json.
+*/
+struct json_default_base {};
+
+template<class T>
+using json_base_class = typename std::conditional <
+ std::is_same<T, void>::value,
+ json_default_base,
+ T
+ >::type;
+
+} // namespace detail
+NLOHMANN_JSON_NAMESPACE_END
+
// #include <nlohmann/detail/json_pointer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
const char* p = s.c_str();
char* p_end = nullptr;
errno = 0; // strtoull doesn't reset errno
- unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
+ const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
if (p == p_end // invalid input or empty string
|| errno == ERANGE // out of range
|| JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
if (reference_token == "-")
{
// explicitly treat "-" as index beyond the end
- ptr = &ptr->operator[](ptr->m_value.array->size());
+ ptr = &ptr->operator[](ptr->m_data.m_value.array->size());
}
else
{
{
// "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, detail::concat(
- "array index '-' (", std::to_string(ptr->m_value.array->size()),
+ "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
") is out of range"), ptr));
}
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" cannot be used for const access
- JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_value.array->size()), ") is out of range"), ptr));
+ JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
}
// use unchecked array access
{
// "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, detail::concat(
- "array index '-' (", std::to_string(ptr->m_value.array->size()),
+ "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
") is out of range"), ptr));
}
{
case detail::value_t::array:
{
- if (value.m_value.array->empty())
+ if (value.m_data.m_value.array->empty())
{
// flatten empty array as null
result[reference_string] = nullptr;
else
{
// iterate array and use index as reference string
- for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
+ for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
{
flatten(detail::concat(reference_string, '/', std::to_string(i)),
- value.m_value.array->operator[](i), result);
+ value.m_data.m_value.array->operator[](i), result);
}
}
break;
case detail::value_t::object:
{
- if (value.m_value.object->empty())
+ if (value.m_data.m_value.object->empty())
{
// flatten empty object as null
result[reference_string] = nullptr;
else
{
// iterate object and use keys as reference string
- for (const auto& element : *value.m_value.object)
+ for (const auto& element : *value.m_data.m_value.object)
{
flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
}
BasicJsonType result;
// iterate the JSON object values
- for (const auto& element : *value.m_value.object)
+ for (const auto& element : *value.m_data.m_value.object)
{
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
{
// #include <nlohmann/detail/json_ref.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/output/binary_writer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/output/output_adapters.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
{
case value_t::object:
{
- write_bson_object(*j.m_value.object);
+ write_bson_object(*j.m_data.m_value.object);
break;
}
case value_t::boolean:
{
- oa->write_character(j.m_value.boolean
+ oa->write_character(j.m_data.m_value.boolean
? to_char_type(0xF5)
: to_char_type(0xF4));
break;
case value_t::number_integer:
{
- if (j.m_value.number_integer >= 0)
+ if (j.m_data.m_value.number_integer >= 0)
{
// CBOR does not differentiate between positive signed
// integers and unsigned integers. Therefore, we used the
// code from the value_t::number_unsigned case here.
- if (j.m_value.number_integer <= 0x17)
+ if (j.m_data.m_value.number_integer <= 0x17)
{
- write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+ else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{
oa->write_character(to_char_type(0x18));
- write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
+ else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
{
oa->write_character(to_char_type(0x19));
- write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
+ else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
{
oa->write_character(to_char_type(0x1A));
- write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
}
else
{
oa->write_character(to_char_type(0x1B));
- write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
}
}
else
{
// The conversions below encode the sign in the first
// byte, and the value is converted to a positive number.
- const auto positive_number = -1 - j.m_value.number_integer;
- if (j.m_value.number_integer >= -24)
+ const auto positive_number = -1 - j.m_data.m_value.number_integer;
+ if (j.m_data.m_value.number_integer >= -24)
{
write_number(static_cast<std::uint8_t>(0x20 + positive_number));
}
case value_t::number_unsigned:
{
- if (j.m_value.number_unsigned <= 0x17)
+ if (j.m_data.m_value.number_unsigned <= 0x17)
{
- write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{
oa->write_character(to_char_type(0x18));
- write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{
oa->write_character(to_char_type(0x19));
- write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
+ write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{
oa->write_character(to_char_type(0x1A));
- write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
+ write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));
}
else
{
oa->write_character(to_char_type(0x1B));
- write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
+ write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
}
break;
}
case value_t::number_float:
{
- if (std::isnan(j.m_value.number_float))
+ if (std::isnan(j.m_data.m_value.number_float))
{
// NaN is 0xf97e00 in CBOR
oa->write_character(to_char_type(0xF9));
oa->write_character(to_char_type(0x7E));
oa->write_character(to_char_type(0x00));
}
- else if (std::isinf(j.m_value.number_float))
+ else if (std::isinf(j.m_data.m_value.number_float))
{
// Infinity is 0xf97c00, -Infinity is 0xf9fc00
oa->write_character(to_char_type(0xf9));
- oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
+ oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
oa->write_character(to_char_type(0x00));
}
else
{
- write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
+ write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor);
}
break;
}
case value_t::string:
{
// step 1: write control byte and the string length
- const auto N = j.m_value.string->size();
+ const auto N = j.m_data.m_value.string->size();
if (N <= 0x17)
{
write_number(static_cast<std::uint8_t>(0x60 + N));
// step 2: write the string
oa->write_characters(
- reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
- j.m_value.string->size());
+ reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
+ j.m_data.m_value.string->size());
break;
}
case value_t::array:
{
// step 1: write control byte and the array size
- const auto N = j.m_value.array->size();
+ const auto N = j.m_data.m_value.array->size();
if (N <= 0x17)
{
write_number(static_cast<std::uint8_t>(0x80 + N));
// LCOV_EXCL_STOP
// step 2: write each element
- for (const auto& el : *j.m_value.array)
+ for (const auto& el : *j.m_data.m_value.array)
{
write_cbor(el);
}
case value_t::binary:
{
- if (j.m_value.binary->has_subtype())
+ if (j.m_data.m_value.binary->has_subtype())
{
- if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
+ if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
{
write_number(static_cast<std::uint8_t>(0xd8));
- write_number(static_cast<std::uint8_t>(j.m_value.binary->subtype()));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.binary->subtype()));
}
- else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
+ else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
{
write_number(static_cast<std::uint8_t>(0xd9));
- write_number(static_cast<std::uint16_t>(j.m_value.binary->subtype()));
+ write_number(static_cast<std::uint16_t>(j.m_data.m_value.binary->subtype()));
}
- else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
+ else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
{
write_number(static_cast<std::uint8_t>(0xda));
- write_number(static_cast<std::uint32_t>(j.m_value.binary->subtype()));
+ write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
}
- else if (j.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
+ else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
{
write_number(static_cast<std::uint8_t>(0xdb));
- write_number(static_cast<std::uint64_t>(j.m_value.binary->subtype()));
+ write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
}
}
// step 1: write control byte and the binary array size
- const auto N = j.m_value.binary->size();
+ const auto N = j.m_data.m_value.binary->size();
if (N <= 0x17)
{
write_number(static_cast<std::uint8_t>(0x40 + N));
// step 2: write each element
oa->write_characters(
- reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+ reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
N);
break;
case value_t::object:
{
// step 1: write control byte and the object size
- const auto N = j.m_value.object->size();
+ const auto N = j.m_data.m_value.object->size();
if (N <= 0x17)
{
write_number(static_cast<std::uint8_t>(0xA0 + N));
// LCOV_EXCL_STOP
// step 2: write each element
- for (const auto& el : *j.m_value.object)
+ for (const auto& el : *j.m_data.m_value.object)
{
write_cbor(el.first);
write_cbor(el.second);
case value_t::boolean: // true and false
{
- oa->write_character(j.m_value.boolean
+ oa->write_character(j.m_data.m_value.boolean
? to_char_type(0xC3)
: to_char_type(0xC2));
break;
case value_t::number_integer:
{
- if (j.m_value.number_integer >= 0)
+ if (j.m_data.m_value.number_integer >= 0)
{
// MessagePack does not differentiate between positive
// signed integers and unsigned integers. Therefore, we used
// the code from the value_t::number_unsigned case here.
- if (j.m_value.number_unsigned < 128)
+ if (j.m_data.m_value.number_unsigned < 128)
{
// positive fixnum
- write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{
// uint 8
oa->write_character(to_char_type(0xCC));
- write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{
// uint 16
oa->write_character(to_char_type(0xCD));
- write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{
// uint 32
oa->write_character(to_char_type(0xCE));
- write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{
// uint 64
oa->write_character(to_char_type(0xCF));
- write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
}
}
else
{
- if (j.m_value.number_integer >= -32)
+ if (j.m_data.m_value.number_integer >= -32)
{
// negative fixnum
- write_number(static_cast<std::int8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
- j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+ else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
+ j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{
// int 8
oa->write_character(to_char_type(0xD0));
- write_number(static_cast<std::int8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
- j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+ else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
+ j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{
// int 16
oa->write_character(to_char_type(0xD1));
- write_number(static_cast<std::int16_t>(j.m_value.number_integer));
+ write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
- j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+ else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
+ j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{
// int 32
oa->write_character(to_char_type(0xD2));
- write_number(static_cast<std::int32_t>(j.m_value.number_integer));
+ write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
- j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+ else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
+ j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{
// int 64
oa->write_character(to_char_type(0xD3));
- write_number(static_cast<std::int64_t>(j.m_value.number_integer));
+ write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer));
}
}
break;
case value_t::number_unsigned:
{
- if (j.m_value.number_unsigned < 128)
+ if (j.m_data.m_value.number_unsigned < 128)
{
// positive fixnum
- write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{
// uint 8
oa->write_character(to_char_type(0xCC));
- write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{
// uint 16
oa->write_character(to_char_type(0xCD));
- write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{
// uint 32
oa->write_character(to_char_type(0xCE));
- write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+ else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{
// uint 64
oa->write_character(to_char_type(0xCF));
- write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
+ write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
}
break;
}
case value_t::number_float:
{
- write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
+ write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack);
break;
}
case value_t::string:
{
// step 1: write control byte and the string length
- const auto N = j.m_value.string->size();
+ const auto N = j.m_data.m_value.string->size();
if (N <= 31)
{
// fixstr
// step 2: write the string
oa->write_characters(
- reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
- j.m_value.string->size());
+ reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
+ j.m_data.m_value.string->size());
break;
}
case value_t::array:
{
// step 1: write control byte and the array size
- const auto N = j.m_value.array->size();
+ const auto N = j.m_data.m_value.array->size();
if (N <= 15)
{
// fixarray
}
// step 2: write each element
- for (const auto& el : *j.m_value.array)
+ for (const auto& el : *j.m_data.m_value.array)
{
write_msgpack(el);
}
{
// step 0: determine if the binary type has a set subtype to
// determine whether or not to use the ext or fixext types
- const bool use_ext = j.m_value.binary->has_subtype();
+ const bool use_ext = j.m_data.m_value.binary->has_subtype();
// step 1: write control byte and the byte string length
- const auto N = j.m_value.binary->size();
+ const auto N = j.m_data.m_value.binary->size();
if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
std::uint8_t output_type{};
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
- std::uint8_t output_type = use_ext
- ? 0xC8 // ext 16
- : 0xC5; // bin 16
+ const std::uint8_t output_type = use_ext
+ ? 0xC8 // ext 16
+ : 0xC5; // bin 16
oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint16_t>(N));
}
else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{
- std::uint8_t output_type = use_ext
- ? 0xC9 // ext 32
- : 0xC6; // bin 32
+ const std::uint8_t output_type = use_ext
+ ? 0xC9 // ext 32
+ : 0xC6; // bin 32
oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint32_t>(N));
// step 1.5: if this is an ext type, write the subtype
if (use_ext)
{
- write_number(static_cast<std::int8_t>(j.m_value.binary->subtype()));
+ write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
}
// step 2: write the byte string
oa->write_characters(
- reinterpret_cast<const CharType*>(j.m_value.binary->data()),
+ reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
N);
break;
case value_t::object:
{
// step 1: write control byte and the object size
- const auto N = j.m_value.object->size();
+ const auto N = j.m_data.m_value.object->size();
if (N <= 15)
{
// fixmap
}
// step 2: write each element
- for (const auto& el : *j.m_value.object)
+ for (const auto& el : *j.m_data.m_value.object)
{
write_msgpack(el.first);
write_msgpack(el.second);
{
if (add_prefix)
{
- oa->write_character(j.m_value.boolean
+ oa->write_character(j.m_data.m_value.boolean
? to_char_type('T')
: to_char_type('F'));
}
case value_t::number_integer:
{
- write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata);
break;
}
case value_t::number_unsigned:
{
- write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata);
break;
}
case value_t::number_float:
{
- write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata);
break;
}
{
oa->write_character(to_char_type('S'));
}
- write_number_with_ubjson_prefix(j.m_value.string->size(), true, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
oa->write_characters(
- reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
- j.m_value.string->size());
+ reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
+ j.m_data.m_value.string->size());
break;
}
}
bool prefix_required = true;
- if (use_type && !j.m_value.array->empty())
+ if (use_type && !j.m_data.m_value.array->empty())
{
JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
if (use_count)
{
oa->write_character(to_char_type('#'));
- write_number_with_ubjson_prefix(j.m_value.array->size(), true, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata);
}
- for (const auto& el : *j.m_value.array)
+ for (const auto& el : *j.m_data.m_value.array)
{
write_ubjson(el, use_count, use_type, prefix_required, use_bjdata);
}
oa->write_character(to_char_type('['));
}
- if (use_type && !j.m_value.binary->empty())
+ if (use_type && !j.m_data.m_value.binary->empty())
{
JSON_ASSERT(use_count);
oa->write_character(to_char_type('$'));
if (use_count)
{
oa->write_character(to_char_type('#'));
- write_number_with_ubjson_prefix(j.m_value.binary->size(), true, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata);
}
if (use_type)
{
oa->write_characters(
- reinterpret_cast<const CharType*>(j.m_value.binary->data()),
- j.m_value.binary->size());
+ reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
+ j.m_data.m_value.binary->size());
}
else
{
- for (size_t i = 0; i < j.m_value.binary->size(); ++i)
+ for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
{
oa->write_character(to_char_type('U'));
- oa->write_character(j.m_value.binary->data()[i]);
+ oa->write_character(j.m_data.m_value.binary->data()[i]);
}
}
case value_t::object:
{
- if (use_bjdata && j.m_value.object->size() == 3 && j.m_value.object->find("_ArrayType_") != j.m_value.object->end() && j.m_value.object->find("_ArraySize_") != j.m_value.object->end() && j.m_value.object->find("_ArrayData_") != j.m_value.object->end())
+ if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end())
{
- if (!write_bjdata_ndarray(*j.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
+ if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
{
break;
}
}
bool prefix_required = true;
- if (use_type && !j.m_value.object->empty())
+ if (use_type && !j.m_data.m_value.object->empty())
{
JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
if (use_count)
{
oa->write_character(to_char_type('#'));
- write_number_with_ubjson_prefix(j.m_value.object->size(), true, use_bjdata);
+ write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata);
}
- for (const auto& el : *j.m_value.object)
+ for (const auto& el : *j.m_data.m_value.object)
{
write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
oa->write_characters(
void write_bson_unsigned(const string_t& name,
const BasicJsonType& j)
{
- if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+ if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{
write_bson_entry_header(name, 0x10 /* int32 */);
- write_number<std::int32_t>(static_cast<std::int32_t>(j.m_value.number_unsigned), true);
+ write_number<std::int32_t>(static_cast<std::int32_t>(j.m_data.m_value.number_unsigned), true);
}
- else if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+ else if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{
write_bson_entry_header(name, 0x12 /* int64 */);
- write_number<std::int64_t>(static_cast<std::int64_t>(j.m_value.number_unsigned), true);
+ write_number<std::int64_t>(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned), true);
}
else
{
- JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
+ JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
}
}
switch (j.type())
{
case value_t::object:
- return header_size + calc_bson_object_size(*j.m_value.object);
+ return header_size + calc_bson_object_size(*j.m_data.m_value.object);
case value_t::array:
- return header_size + calc_bson_array_size(*j.m_value.array);
+ return header_size + calc_bson_array_size(*j.m_data.m_value.array);
case value_t::binary:
- return header_size + calc_bson_binary_size(*j.m_value.binary);
+ return header_size + calc_bson_binary_size(*j.m_data.m_value.binary);
case value_t::boolean:
return header_size + 1ul;
return header_size + 8ul;
case value_t::number_integer:
- return header_size + calc_bson_integer_size(j.m_value.number_integer);
+ return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer);
case value_t::number_unsigned:
- return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
+ return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned);
case value_t::string:
- return header_size + calc_bson_string_size(*j.m_value.string);
+ return header_size + calc_bson_string_size(*j.m_data.m_value.string);
case value_t::null:
return header_size + 0ul;
switch (j.type())
{
case value_t::object:
- return write_bson_object_entry(name, *j.m_value.object);
+ return write_bson_object_entry(name, *j.m_data.m_value.object);
case value_t::array:
- return write_bson_array(name, *j.m_value.array);
+ return write_bson_array(name, *j.m_data.m_value.array);
case value_t::binary:
- return write_bson_binary(name, *j.m_value.binary);
+ return write_bson_binary(name, *j.m_data.m_value.binary);
case value_t::boolean:
- return write_bson_boolean(name, j.m_value.boolean);
+ return write_bson_boolean(name, j.m_data.m_value.boolean);
case value_t::number_float:
- return write_bson_double(name, j.m_value.number_float);
+ return write_bson_double(name, j.m_data.m_value.number_float);
case value_t::number_integer:
- return write_bson_integer(name, j.m_value.number_integer);
+ return write_bson_integer(name, j.m_data.m_value.number_integer);
case value_t::number_unsigned:
return write_bson_unsigned(name, j);
case value_t::string:
- return write_bson_string(name, *j.m_value.string);
+ return write_bson_string(name, *j.m_data.m_value.string);
case value_t::null:
return write_bson_null(name);
*/
static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
{
- std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
- [](size_t result, const typename BasicJsonType::object_t::value_type & el)
+ const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
+ [](size_t result, const typename BasicJsonType::object_t::value_type & el)
{
return result += calc_bson_element_size(el.first, el.second);
});
return 'Z';
case value_t::boolean:
- return j.m_value.boolean ? 'T' : 'F';
+ return j.m_data.m_value.boolean ? 'T' : 'F';
case value_t::number_integer:
{
- if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
+ if ((std::numeric_limits<std::int8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{
return 'i';
}
- if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
+ if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{
return 'U';
}
- if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
+ if ((std::numeric_limits<std::int16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{
return 'I';
}
- if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
+ if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
{
return 'u';
}
- if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
+ if ((std::numeric_limits<std::int32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{
return 'l';
}
- if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
+ if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
{
return 'm';
}
- if ((std::numeric_limits<std::int64_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
+ if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{
return 'L';
}
case value_t::number_unsigned:
{
- if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
+ if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
{
return 'i';
}
- if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
+ if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
{
return 'U';
}
- if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
+ if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
{
return 'I';
}
- if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
+ if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
{
return 'u';
}
- if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
+ if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{
return 'l';
}
- if (use_bjdata && j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
+ if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
{
return 'm';
}
- if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
+ if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{
return 'L';
}
- if (use_bjdata && j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
+ if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{
return 'M';
}
}
case value_t::number_float:
- return get_ubjson_float_prefix(j.m_value.number_float);
+ return get_ubjson_float_prefix(j.m_data.m_value.number_float);
case value_t::string:
return 'S';
std::size_t len = (value.at(key).empty() ? 0 : 1);
for (const auto& el : value.at(key))
{
- len *= static_cast<std::size_t>(el.m_value.number_unsigned);
+ len *= static_cast<std::size_t>(el.m_data.m_value.number_unsigned);
}
key = "_ArrayData_";
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::uint8_t>(el.m_value.number_unsigned), true);
+ write_number(static_cast<std::uint8_t>(el.m_data.m_value.number_unsigned), true);
}
}
else if (dtype == 'i')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::int8_t>(el.m_value.number_integer), true);
+ write_number(static_cast<std::int8_t>(el.m_data.m_value.number_integer), true);
}
}
else if (dtype == 'u')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::uint16_t>(el.m_value.number_unsigned), true);
+ write_number(static_cast<std::uint16_t>(el.m_data.m_value.number_unsigned), true);
}
}
else if (dtype == 'I')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::int16_t>(el.m_value.number_integer), true);
+ write_number(static_cast<std::int16_t>(el.m_data.m_value.number_integer), true);
}
}
else if (dtype == 'm')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::uint32_t>(el.m_value.number_unsigned), true);
+ write_number(static_cast<std::uint32_t>(el.m_data.m_value.number_unsigned), true);
}
}
else if (dtype == 'l')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::int32_t>(el.m_value.number_integer), true);
+ write_number(static_cast<std::int32_t>(el.m_data.m_value.number_integer), true);
}
}
else if (dtype == 'M')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::uint64_t>(el.m_value.number_unsigned), true);
+ write_number(static_cast<std::uint64_t>(el.m_data.m_value.number_unsigned), true);
}
}
else if (dtype == 'L')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<std::int64_t>(el.m_value.number_integer), true);
+ write_number(static_cast<std::int64_t>(el.m_data.m_value.number_integer), true);
}
}
else if (dtype == 'd')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<float>(el.m_value.number_float), true);
+ write_number(static_cast<float>(el.m_data.m_value.number_float), true);
}
}
else if (dtype == 'D')
{
for (const auto& el : value.at(key))
{
- write_number(static_cast<double>(el.m_value.number_float), true);
+ write_number(static_cast<double>(el.m_data.m_value.number_float), true);
}
}
return false;
// #include <nlohmann/detail/output/serializer.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// #include <nlohmann/detail/conversions/to_chars.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// NB: If the neighbors are computed for single-precision numbers, there is a single float
// (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
// value is off by 1 ulp.
-#if 0
+#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if)
const boundaries w = compute_boundaries(static_cast<double>(value));
#else
const boundaries w = compute_boundaries(value);
const unsigned int indent_step,
const unsigned int current_indent = 0)
{
- switch (val.m_type)
+ switch (val.m_data.m_type)
{
case value_t::object:
{
- if (val.m_value.object->empty())
+ if (val.m_data.m_value.object->empty())
{
o->write_characters("{}", 2);
return;
}
// first n-1 elements
- auto i = val.m_value.object->cbegin();
- for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
+ auto i = val.m_data.m_value.object->cbegin();
+ for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
{
o->write_characters(indent_string.c_str(), new_indent);
o->write_character('\"');
}
// last element
- JSON_ASSERT(i != val.m_value.object->cend());
- JSON_ASSERT(std::next(i) == val.m_value.object->cend());
+ JSON_ASSERT(i != val.m_data.m_value.object->cend());
+ JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
o->write_characters(indent_string.c_str(), new_indent);
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
o->write_character('{');
// first n-1 elements
- auto i = val.m_value.object->cbegin();
- for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
+ auto i = val.m_data.m_value.object->cbegin();
+ for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
{
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
}
// last element
- JSON_ASSERT(i != val.m_value.object->cend());
- JSON_ASSERT(std::next(i) == val.m_value.object->cend());
+ JSON_ASSERT(i != val.m_data.m_value.object->cend());
+ JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2);
case value_t::array:
{
- if (val.m_value.array->empty())
+ if (val.m_data.m_value.array->empty())
{
o->write_characters("[]", 2);
return;
}
// first n-1 elements
- for (auto i = val.m_value.array->cbegin();
- i != val.m_value.array->cend() - 1; ++i)
+ for (auto i = val.m_data.m_value.array->cbegin();
+ i != val.m_data.m_value.array->cend() - 1; ++i)
{
o->write_characters(indent_string.c_str(), new_indent);
dump(*i, true, ensure_ascii, indent_step, new_indent);
}
// last element
- JSON_ASSERT(!val.m_value.array->empty());
+ JSON_ASSERT(!val.m_data.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent);
- dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
+ dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
o->write_character('\n');
o->write_characters(indent_string.c_str(), current_indent);
o->write_character('[');
// first n-1 elements
- for (auto i = val.m_value.array->cbegin();
- i != val.m_value.array->cend() - 1; ++i)
+ for (auto i = val.m_data.m_value.array->cbegin();
+ i != val.m_data.m_value.array->cend() - 1; ++i)
{
dump(*i, false, ensure_ascii, indent_step, current_indent);
o->write_character(',');
}
// last element
- JSON_ASSERT(!val.m_value.array->empty());
- dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
+ JSON_ASSERT(!val.m_data.m_value.array->empty());
+ dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
o->write_character(']');
}
case value_t::string:
{
o->write_character('\"');
- dump_escaped(*val.m_value.string, ensure_ascii);
+ dump_escaped(*val.m_data.m_value.string, ensure_ascii);
o->write_character('\"');
return;
}
o->write_characters("\"bytes\": [", 10);
- if (!val.m_value.binary->empty())
+ if (!val.m_data.m_value.binary->empty())
{
- for (auto i = val.m_value.binary->cbegin();
- i != val.m_value.binary->cend() - 1; ++i)
+ for (auto i = val.m_data.m_value.binary->cbegin();
+ i != val.m_data.m_value.binary->cend() - 1; ++i)
{
dump_integer(*i);
o->write_characters(", ", 2);
}
- dump_integer(val.m_value.binary->back());
+ dump_integer(val.m_data.m_value.binary->back());
}
o->write_characters("],\n", 3);
o->write_characters(indent_string.c_str(), new_indent);
o->write_characters("\"subtype\": ", 11);
- if (val.m_value.binary->has_subtype())
+ if (val.m_data.m_value.binary->has_subtype())
{
- dump_integer(val.m_value.binary->subtype());
+ dump_integer(val.m_data.m_value.binary->subtype());
}
else
{
{
o->write_characters("{\"bytes\":[", 10);
- if (!val.m_value.binary->empty())
+ if (!val.m_data.m_value.binary->empty())
{
- for (auto i = val.m_value.binary->cbegin();
- i != val.m_value.binary->cend() - 1; ++i)
+ for (auto i = val.m_data.m_value.binary->cbegin();
+ i != val.m_data.m_value.binary->cend() - 1; ++i)
{
dump_integer(*i);
o->write_character(',');
}
- dump_integer(val.m_value.binary->back());
+ dump_integer(val.m_data.m_value.binary->back());
}
o->write_characters("],\"subtype\":", 12);
- if (val.m_value.binary->has_subtype())
+ if (val.m_data.m_value.binary->has_subtype())
{
- dump_integer(val.m_value.binary->subtype());
+ dump_integer(val.m_data.m_value.binary->subtype());
o->write_character('}');
}
else
case value_t::boolean:
{
- if (val.m_value.boolean)
+ if (val.m_data.m_value.boolean)
{
o->write_characters("true", 4);
}
case value_t::number_integer:
{
- dump_integer(val.m_value.number_integer);
+ dump_integer(val.m_data.m_value.number_integer);
return;
}
case value_t::number_unsigned:
{
- dump_integer(val.m_value.number_unsigned);
+ dump_integer(val.m_data.m_value.number_unsigned);
return;
}
case value_t::number_float:
{
- dump_float(val.m_value.number_float);
+ dump_float(val.m_data.m_value.number_float);
return;
}
? (byte & 0x3fu) | (codep << 6u)
: (0xFFu >> type) & (byte);
- std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
- JSON_ASSERT(index < 400);
+ const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
+ JSON_ASSERT(index < utf8d.size());
state = utf8d[index];
return state;
}
// #include <nlohmann/ordered_map.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
- T & at(KeyType && key)
+ T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
- const T & at(KeyType && key) const
+ const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
- size_type erase(KeyType && key)
+ size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
- size_type count(KeyType && key) const
+ size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
- iterator find(KeyType && key)
+ iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
#if defined(JSON_HAS_CPP_17)
- #include <any>
+ #if JSON_HAS_STATIC_RTTI
+ #include <any>
+ #endif
#include <string_view>
#endif
*/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
+ : public ::nlohmann::detail::json_base_class<CustomBaseClass>
{
private:
template<detail::value_t> friend struct detail::external_constructor;
/// workaround type for MSVC
using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
+ using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
JSON_PRIVATE_UNLESS_TESTED:
// convenience aliases for types residing in namespace detail;
/// @}
-
/////////////////////
// container types //
/////////////////////
/// @}
-
/// @brief returns the allocator associated with the container
/// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
static allocator_type get_allocator()
{
basic_json result;
- result["copyright"] = "(C) 2013-2022 Niels Lohmann";
+ result["copyright"] = "(C) 2013-2023 Niels Lohmann";
result["name"] = "JSON for Modern C++";
result["url"] = "https://github.com/nlohmann/json";
result["version"]["string"] =
result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
#endif
-
#if defined(_MSVC_LANG)
result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
#elif defined(__cplusplus)
return result;
}
-
///////////////////////////
// JSON value data types //
///////////////////////////
object = nullptr; // silence warning, see #821
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
{
- JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.2", nullptr)); // LCOV_EXCL_LINE
+ JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
}
break;
}
void destroy(value_t t)
{
+ if (
+ (t == value_t::object && object == nullptr) ||
+ (t == value_t::array && array == nullptr) ||
+ (t == value_t::string && string == nullptr) ||
+ (t == value_t::binary && binary == nullptr)
+ )
+ {
+ //not initialized (e.g. due to exception in the ctor)
+ return;
+ }
if (t == value_t::array || t == value_t::object)
{
// flatten the current json_value to a heap-allocated stack
// its children to the stack to be processed later
if (current_item.is_array())
{
- std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack));
+ std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
- current_item.m_value.array->clear();
+ current_item.m_data.m_value.array->clear();
}
else if (current_item.is_object())
{
- for (auto&& it : *current_item.m_value.object)
+ for (auto&& it : *current_item.m_data.m_value.object)
{
stack.push_back(std::move(it.second));
}
- current_item.m_value.object->clear();
+ current_item.m_data.m_value.object->clear();
}
// it's now safe that current_item get destructed
*/
void assert_invariant(bool check_parents = true) const noexcept
{
- JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
- JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
- JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
- JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
+ JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);
+ JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);
+ JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);
+ JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);
#if JSON_DIAGNOSTICS
JSON_TRY
void set_parents()
{
#if JSON_DIAGNOSTICS
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::array:
{
- for (auto& element : *m_value.array)
+ for (auto& element : *m_data.m_value.array)
{
element.m_parent = this;
}
case value_t::object:
{
- for (auto& element : *m_value.object)
+ for (auto& element : *m_data.m_value.object)
{
element.second.m_parent = this;
}
{
// see https://github.com/nlohmann/json/issues/2838
JSON_ASSERT(type() == value_t::array);
- if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
+ if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
{
// capacity has changed: update all parents
set_parents();
/// @brief create an empty value with a given type
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(const value_t v)
- : m_type(v), m_value(v)
+ : m_data(v)
{
assert_invariant();
}
*this = nullptr;
break;
case value_t::discarded:
- m_type = value_t::discarded;
+ m_data.m_type = value_t::discarded;
break;
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
}
- JSON_ASSERT(m_type == val.type());
+ JSON_ASSERT(m_data.m_type == val.type());
set_parents();
assert_invariant();
}
bool is_an_object = std::all_of(init.begin(), init.end(),
[](const detail::json_ref<basic_json>& element_ref)
{
- return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();
+ // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;
+ // (many string types can be constructed from 0 via its null-pointer guise, so we get a
+ // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows)
+ return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();
});
// adjust type if type deduction is not wanted
if (is_an_object)
{
// the initializer list is a list of pairs -> create object
- m_type = value_t::object;
- m_value = value_t::object;
+ m_data.m_type = value_t::object;
+ m_data.m_value = value_t::object;
for (auto& element_ref : init)
{
auto element = element_ref.moved_or_copied();
- m_value.object->emplace(
- std::move(*((*element.m_value.array)[0].m_value.string)),
- std::move((*element.m_value.array)[1]));
+ m_data.m_value.object->emplace(
+ std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),
+ std::move((*element.m_data.m_value.array)[1]));
}
}
else
{
// the initializer list describes an array -> create array
- m_type = value_t::array;
- m_value.array = create<array_t>(init.begin(), init.end());
+ m_data.m_type = value_t::array;
+ m_data.m_value.array = create<array_t>(init.begin(), init.end());
}
set_parents();
static basic_json binary(const typename binary_t::container_type& init)
{
auto res = basic_json();
- res.m_type = value_t::binary;
- res.m_value = init;
+ res.m_data.m_type = value_t::binary;
+ res.m_data.m_value = init;
return res;
}
static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
{
auto res = basic_json();
- res.m_type = value_t::binary;
- res.m_value = binary_t(init, subtype);
+ res.m_data.m_type = value_t::binary;
+ res.m_data.m_value = binary_t(init, subtype);
return res;
}
static basic_json binary(typename binary_t::container_type&& init)
{
auto res = basic_json();
- res.m_type = value_t::binary;
- res.m_value = std::move(init);
+ res.m_data.m_type = value_t::binary;
+ res.m_data.m_value = std::move(init);
return res;
}
static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
{
auto res = basic_json();
- res.m_type = value_t::binary;
- res.m_value = binary_t(std::move(init), subtype);
+ res.m_data.m_type = value_t::binary;
+ res.m_data.m_value = binary_t(std::move(init), subtype);
return res;
}
/// @brief construct an array with count copies of given value
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
- basic_json(size_type cnt, const basic_json& val)
- : m_type(value_t::array)
+ basic_json(size_type cnt, const basic_json& val):
+ m_data{cnt, val}
{
- m_value.array = create<array_t>(cnt, val);
set_parents();
assert_invariant();
}
}
// copy type from first iterator
- m_type = first.m_object->m_type;
+ m_data.m_type = first.m_object->m_data.m_type;
// check if iterator range is complete for primitive values
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::boolean:
case value_t::number_float:
break;
}
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::number_integer:
{
- m_value.number_integer = first.m_object->m_value.number_integer;
+ m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;
break;
}
case value_t::number_unsigned:
{
- m_value.number_unsigned = first.m_object->m_value.number_unsigned;
+ m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;
break;
}
case value_t::number_float:
{
- m_value.number_float = first.m_object->m_value.number_float;
+ m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;
break;
}
case value_t::boolean:
{
- m_value.boolean = first.m_object->m_value.boolean;
+ m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;
break;
}
case value_t::string:
{
- m_value = *first.m_object->m_value.string;
+ m_data.m_value = *first.m_object->m_data.m_value.string;
break;
}
case value_t::object:
{
- m_value.object = create<object_t>(first.m_it.object_iterator,
- last.m_it.object_iterator);
+ m_data.m_value.object = create<object_t>(first.m_it.object_iterator,
+ last.m_it.object_iterator);
break;
}
case value_t::array:
{
- m_value.array = create<array_t>(first.m_it.array_iterator,
- last.m_it.array_iterator);
+ m_data.m_value.array = create<array_t>(first.m_it.array_iterator,
+ last.m_it.array_iterator);
break;
}
case value_t::binary:
{
- m_value = *first.m_object->m_value.binary;
+ m_data.m_value = *first.m_object->m_data.m_value.binary;
break;
}
assert_invariant();
}
-
///////////////////////////////////////
// other constructors and destructor //
///////////////////////////////////////
/// @brief copy constructor
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(const basic_json& other)
- : m_type(other.m_type)
+ : json_base_class_t(other)
{
+ m_data.m_type = other.m_data.m_type;
// check of passed value is valid
other.assert_invariant();
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::object:
{
- m_value = *other.m_value.object;
+ m_data.m_value = *other.m_data.m_value.object;
break;
}
case value_t::array:
{
- m_value = *other.m_value.array;
+ m_data.m_value = *other.m_data.m_value.array;
break;
}
case value_t::string:
{
- m_value = *other.m_value.string;
+ m_data.m_value = *other.m_data.m_value.string;
break;
}
case value_t::boolean:
{
- m_value = other.m_value.boolean;
+ m_data.m_value = other.m_data.m_value.boolean;
break;
}
case value_t::number_integer:
{
- m_value = other.m_value.number_integer;
+ m_data.m_value = other.m_data.m_value.number_integer;
break;
}
case value_t::number_unsigned:
{
- m_value = other.m_value.number_unsigned;
+ m_data.m_value = other.m_data.m_value.number_unsigned;
break;
}
case value_t::number_float:
{
- m_value = other.m_value.number_float;
+ m_data.m_value = other.m_data.m_value.number_float;
break;
}
case value_t::binary:
{
- m_value = *other.m_value.binary;
+ m_data.m_value = *other.m_data.m_value.binary;
break;
}
/// @brief move constructor
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
basic_json(basic_json&& other) noexcept
- : m_type(std::move(other.m_type)),
- m_value(std::move(other.m_value))
+ : json_base_class_t(std::forward<json_base_class_t>(other)),
+ m_data(std::move(other.m_data))
{
// check that passed value is valid
other.assert_invariant(false);
// invalidate payload
- other.m_type = value_t::null;
- other.m_value = {};
+ other.m_data.m_type = value_t::null;
+ other.m_data.m_value = {};
set_parents();
assert_invariant();
std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value&&
std::is_nothrow_move_constructible<json_value>::value&&
- std::is_nothrow_move_assignable<json_value>::value
+ std::is_nothrow_move_assignable<json_value>::value&&
+ std::is_nothrow_move_assignable<json_base_class_t>::value
)
{
// check that passed value is valid
other.assert_invariant();
using std::swap;
- swap(m_type, other.m_type);
- swap(m_value, other.m_value);
+ swap(m_data.m_type, other.m_data.m_type);
+ swap(m_data.m_value, other.m_data.m_value);
+ json_base_class_t::operator=(std::move(other));
set_parents();
assert_invariant();
~basic_json() noexcept
{
assert_invariant(false);
- m_value.destroy(m_type);
}
/// @}
/// @sa https://json.nlohmann.me/api/basic_json/type/
constexpr value_t type() const noexcept
{
- return m_type;
+ return m_data.m_type;
}
/// @brief return whether type is primitive
/// @sa https://json.nlohmann.me/api/basic_json/is_null/
constexpr bool is_null() const noexcept
{
- return m_type == value_t::null;
+ return m_data.m_type == value_t::null;
}
/// @brief return whether value is a boolean
/// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
constexpr bool is_boolean() const noexcept
{
- return m_type == value_t::boolean;
+ return m_data.m_type == value_t::boolean;
}
/// @brief return whether value is a number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
constexpr bool is_number_integer() const noexcept
{
- return m_type == value_t::number_integer || m_type == value_t::number_unsigned;
+ return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
}
/// @brief return whether value is an unsigned integer number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
constexpr bool is_number_unsigned() const noexcept
{
- return m_type == value_t::number_unsigned;
+ return m_data.m_type == value_t::number_unsigned;
}
/// @brief return whether value is a floating-point number
/// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
constexpr bool is_number_float() const noexcept
{
- return m_type == value_t::number_float;
+ return m_data.m_type == value_t::number_float;
}
/// @brief return whether value is an object
/// @sa https://json.nlohmann.me/api/basic_json/is_object/
constexpr bool is_object() const noexcept
{
- return m_type == value_t::object;
+ return m_data.m_type == value_t::object;
}
/// @brief return whether value is an array
/// @sa https://json.nlohmann.me/api/basic_json/is_array/
constexpr bool is_array() const noexcept
{
- return m_type == value_t::array;
+ return m_data.m_type == value_t::array;
}
/// @brief return whether value is a string
/// @sa https://json.nlohmann.me/api/basic_json/is_string/
constexpr bool is_string() const noexcept
{
- return m_type == value_t::string;
+ return m_data.m_type == value_t::string;
}
/// @brief return whether value is a binary array
/// @sa https://json.nlohmann.me/api/basic_json/is_binary/
constexpr bool is_binary() const noexcept
{
- return m_type == value_t::binary;
+ return m_data.m_type == value_t::binary;
}
/// @brief return whether value is discarded
/// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
constexpr bool is_discarded() const noexcept
{
- return m_type == value_t::discarded;
+ return m_data.m_type == value_t::discarded;
}
/// @brief return the type of the JSON value (implicit)
/// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
constexpr operator value_t() const noexcept
{
- return m_type;
+ return m_data.m_type;
}
/// @}
{
if (JSON_HEDLEY_LIKELY(is_boolean()))
{
- return m_value.boolean;
+ return m_data.m_value.boolean;
}
JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
/// get a pointer to the value (object)
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
{
- return is_object() ? m_value.object : nullptr;
+ return is_object() ? m_data.m_value.object : nullptr;
}
/// get a pointer to the value (object)
constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
{
- return is_object() ? m_value.object : nullptr;
+ return is_object() ? m_data.m_value.object : nullptr;
}
/// get a pointer to the value (array)
array_t* get_impl_ptr(array_t* /*unused*/) noexcept
{
- return is_array() ? m_value.array : nullptr;
+ return is_array() ? m_data.m_value.array : nullptr;
}
/// get a pointer to the value (array)
constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
{
- return is_array() ? m_value.array : nullptr;
+ return is_array() ? m_data.m_value.array : nullptr;
}
/// get a pointer to the value (string)
string_t* get_impl_ptr(string_t* /*unused*/) noexcept
{
- return is_string() ? m_value.string : nullptr;
+ return is_string() ? m_data.m_value.string : nullptr;
}
/// get a pointer to the value (string)
constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
{
- return is_string() ? m_value.string : nullptr;
+ return is_string() ? m_data.m_value.string : nullptr;
}
/// get a pointer to the value (boolean)
boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
{
- return is_boolean() ? &m_value.boolean : nullptr;
+ return is_boolean() ? &m_data.m_value.boolean : nullptr;
}
/// get a pointer to the value (boolean)
constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
{
- return is_boolean() ? &m_value.boolean : nullptr;
+ return is_boolean() ? &m_data.m_value.boolean : nullptr;
}
/// get a pointer to the value (integer number)
number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
{
- return is_number_integer() ? &m_value.number_integer : nullptr;
+ return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
}
/// get a pointer to the value (integer number)
constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
{
- return is_number_integer() ? &m_value.number_integer : nullptr;
+ return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
}
/// get a pointer to the value (unsigned number)
number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
{
- return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+ return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
}
/// get a pointer to the value (unsigned number)
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
{
- return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+ return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
}
/// get a pointer to the value (floating-point number)
number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
{
- return is_number_float() ? &m_value.number_float : nullptr;
+ return is_number_float() ? &m_data.m_value.number_float : nullptr;
}
/// get a pointer to the value (floating-point number)
constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
{
- return is_number_float() ? &m_value.number_float : nullptr;
+ return is_number_float() ? &m_data.m_value.number_float : nullptr;
}
/// get a pointer to the value (binary)
binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
{
- return is_binary() ? m_value.binary : nullptr;
+ return is_binary() ? m_data.m_value.binary : nullptr;
}
/// get a pointer to the value (binary)
constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
{
- return is_binary() ? m_value.binary : nullptr;
+ return is_binary() ? m_data.m_value.binary : nullptr;
}
/*!
#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
detail::negation<std::is_same<ValueType, std::string_view>>,
#endif
-#if defined(JSON_HAS_CPP_17)
+#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI
detail::negation<std::is_same<ValueType, std::any>>,
#endif
detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
/// @}
-
////////////////////
// element access //
////////////////////
{
JSON_TRY
{
- return set_parent(m_value.array->at(idx));
+ return set_parent(m_data.m_value.array->at(idx));
}
JSON_CATCH (std::out_of_range&)
{
{
JSON_TRY
{
- return m_value.array->at(idx);
+ return m_data.m_value.array->at(idx);
}
JSON_CATCH (std::out_of_range&)
{
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
- auto it = m_value.object->find(key);
- if (it == m_value.object->end())
+ auto it = m_data.m_value.object->find(key);
+ if (it == m_data.m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
- auto it = m_value.object->find(std::forward<KeyType>(key));
- if (it == m_value.object->end())
+ auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
+ if (it == m_data.m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
}
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
- auto it = m_value.object->find(key);
- if (it == m_value.object->end())
+ auto it = m_data.m_value.object->find(key);
+ if (it == m_data.m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
}
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
}
- auto it = m_value.object->find(std::forward<KeyType>(key));
- if (it == m_value.object->end())
+ auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
+ if (it == m_data.m_value.object->end())
{
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
}
// implicitly convert null value to an empty array
if (is_null())
{
- m_type = value_t::array;
- m_value.array = create<array_t>();
+ m_data.m_type = value_t::array;
+ m_data.m_value.array = create<array_t>();
assert_invariant();
}
if (JSON_HEDLEY_LIKELY(is_array()))
{
// fill up array with null values if given idx is outside range
- if (idx >= m_value.array->size())
+ if (idx >= m_data.m_value.array->size())
{
#if JSON_DIAGNOSTICS
// remember array size & capacity before resizing
- const auto old_size = m_value.array->size();
- const auto old_capacity = m_value.array->capacity();
+ const auto old_size = m_data.m_value.array->size();
+ const auto old_capacity = m_data.m_value.array->capacity();
#endif
- m_value.array->resize(idx + 1);
+ m_data.m_value.array->resize(idx + 1);
#if JSON_DIAGNOSTICS
- if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity))
+ if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
{
// capacity has changed: update all parents
set_parents();
assert_invariant();
}
- return m_value.array->operator[](idx);
+ return m_data.m_value.array->operator[](idx);
}
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
// const operator[] only works for arrays
if (JSON_HEDLEY_LIKELY(is_array()))
{
- return m_value.array->operator[](idx);
+ return m_data.m_value.array->operator[](idx);
}
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
// implicitly convert null value to an empty object
if (is_null())
{
- m_type = value_t::object;
- m_value.object = create<object_t>();
+ m_data.m_type = value_t::object;
+ m_data.m_value.object = create<object_t>();
assert_invariant();
}
// operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
- auto result = m_value.object->emplace(std::move(key), nullptr);
+ auto result = m_data.m_value.object->emplace(std::move(key), nullptr);
return set_parent(result.first->second);
}
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
- auto it = m_value.object->find(key);
- JSON_ASSERT(it != m_value.object->end());
+ auto it = m_data.m_value.object->find(key);
+ JSON_ASSERT(it != m_data.m_value.object->end());
return it->second;
}
// implicitly convert null value to an empty object
if (is_null())
{
- m_type = value_t::object;
- m_value.object = create<object_t>();
+ m_data.m_type = value_t::object;
+ m_data.m_value.object = create<object_t>();
assert_invariant();
}
// operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
- auto result = m_value.object->emplace(std::forward<KeyType>(key), nullptr);
+ auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
return set_parent(result.first->second);
}
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
- auto it = m_value.object->find(std::forward<KeyType>(key));
- JSON_ASSERT(it != m_value.object->end());
+ auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
+ JSON_ASSERT(it != m_data.m_value.object->end());
return it->second;
}
IteratorType result = end();
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::boolean:
case value_t::number_float:
if (is_string())
{
AllocatorType<string_t> alloc;
- std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
- std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
- m_value.string = nullptr;
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
+ m_data.m_value.string = nullptr;
}
else if (is_binary())
{
AllocatorType<binary_t> alloc;
- std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
- std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
- m_value.binary = nullptr;
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
+ m_data.m_value.binary = nullptr;
}
- m_type = value_t::null;
+ m_data.m_type = value_t::null;
assert_invariant();
break;
}
case value_t::object:
{
- result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
+ result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
break;
}
case value_t::array:
{
- result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
+ result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);
break;
}
IteratorType result = end();
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::boolean:
case value_t::number_float:
if (is_string())
{
AllocatorType<string_t> alloc;
- std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
- std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
- m_value.string = nullptr;
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
+ m_data.m_value.string = nullptr;
}
else if (is_binary())
{
AllocatorType<binary_t> alloc;
- std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary);
- std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1);
- m_value.binary = nullptr;
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
+ m_data.m_value.binary = nullptr;
}
- m_type = value_t::null;
+ m_data.m_type = value_t::null;
assert_invariant();
break;
}
case value_t::object:
{
- result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
+ result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,
last.m_it.object_iterator);
break;
}
case value_t::array:
{
- result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
+ result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,
last.m_it.array_iterator);
break;
}
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
}
- return m_value.object->erase(std::forward<KeyType>(key));
+ return m_data.m_value.object->erase(std::forward<KeyType>(key));
}
template < typename KeyType, detail::enable_if_t <
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
}
- const auto it = m_value.object->find(std::forward<KeyType>(key));
- if (it != m_value.object->end())
+ const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
+ if (it != m_data.m_value.object->end())
{
- m_value.object->erase(it);
+ m_data.m_value.object->erase(it);
return 1;
}
return 0;
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
}
- m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
+ m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
}
else
{
/// @}
-
////////////
// lookup //
////////////
if (is_object())
{
- result.m_it.object_iterator = m_value.object->find(key);
+ result.m_it.object_iterator = m_data.m_value.object->find(key);
}
return result;
if (is_object())
{
- result.m_it.object_iterator = m_value.object->find(key);
+ result.m_it.object_iterator = m_data.m_value.object->find(key);
}
return result;
if (is_object())
{
- result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
+ result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
}
return result;
if (is_object())
{
- result.m_it.object_iterator = m_value.object->find(std::forward<KeyType>(key));
+ result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
}
return result;
size_type count(const typename object_t::key_type& key) const
{
// return 0 for all nonobject types
- return is_object() ? m_value.object->count(key) : 0;
+ return is_object() ? m_data.m_value.object->count(key) : 0;
}
/// @brief returns the number of occurrences of a key in a JSON object
size_type count(KeyType && key) const
{
// return 0 for all nonobject types
- return is_object() ? m_value.object->count(std::forward<KeyType>(key)) : 0;
+ return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
}
/// @brief check the existence of an element in a JSON object
/// @sa https://json.nlohmann.me/api/basic_json/contains/
bool contains(const typename object_t::key_type& key) const
{
- return is_object() && m_value.object->find(key) != m_value.object->end();
+ return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
}
/// @brief check the existence of an element in a JSON object
detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
bool contains(KeyType && key) const
{
- return is_object() && m_value.object->find(std::forward<KeyType>(key)) != m_value.object->end();
+ return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
}
/// @brief check the existence of an element in a JSON object given a JSON pointer
/// @}
-
///////////////
// iterators //
///////////////
/// @}
-
//////////////
// capacity //
//////////////
/// @sa https://json.nlohmann.me/api/basic_json/empty/
bool empty() const noexcept
{
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::null:
{
case value_t::array:
{
// delegate call to array_t::empty()
- return m_value.array->empty();
+ return m_data.m_value.array->empty();
}
case value_t::object:
{
// delegate call to object_t::empty()
- return m_value.object->empty();
+ return m_data.m_value.object->empty();
}
case value_t::string:
/// @sa https://json.nlohmann.me/api/basic_json/size/
size_type size() const noexcept
{
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::null:
{
case value_t::array:
{
// delegate call to array_t::size()
- return m_value.array->size();
+ return m_data.m_value.array->size();
}
case value_t::object:
{
// delegate call to object_t::size()
- return m_value.object->size();
+ return m_data.m_value.object->size();
}
case value_t::string:
/// @sa https://json.nlohmann.me/api/basic_json/max_size/
size_type max_size() const noexcept
{
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::array:
{
// delegate call to array_t::max_size()
- return m_value.array->max_size();
+ return m_data.m_value.array->max_size();
}
case value_t::object:
{
// delegate call to object_t::max_size()
- return m_value.object->max_size();
+ return m_data.m_value.object->max_size();
}
case value_t::null:
/// @}
-
///////////////
// modifiers //
///////////////
/// @sa https://json.nlohmann.me/api/basic_json/clear/
void clear() noexcept
{
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::number_integer:
{
- m_value.number_integer = 0;
+ m_data.m_value.number_integer = 0;
break;
}
case value_t::number_unsigned:
{
- m_value.number_unsigned = 0;
+ m_data.m_value.number_unsigned = 0;
break;
}
case value_t::number_float:
{
- m_value.number_float = 0.0;
+ m_data.m_value.number_float = 0.0;
break;
}
case value_t::boolean:
{
- m_value.boolean = false;
+ m_data.m_value.boolean = false;
break;
}
case value_t::string:
{
- m_value.string->clear();
+ m_data.m_value.string->clear();
break;
}
case value_t::binary:
{
- m_value.binary->clear();
+ m_data.m_value.binary->clear();
break;
}
case value_t::array:
{
- m_value.array->clear();
+ m_data.m_value.array->clear();
break;
}
case value_t::object:
{
- m_value.object->clear();
+ m_data.m_value.object->clear();
break;
}
// transform null object into an array
if (is_null())
{
- m_type = value_t::array;
- m_value = value_t::array;
+ m_data.m_type = value_t::array;
+ m_data.m_value = value_t::array;
assert_invariant();
}
// add element to array (move semantics)
- const auto old_capacity = m_value.array->capacity();
- m_value.array->push_back(std::move(val));
- set_parent(m_value.array->back(), old_capacity);
+ const auto old_capacity = m_data.m_value.array->capacity();
+ m_data.m_value.array->push_back(std::move(val));
+ set_parent(m_data.m_value.array->back(), old_capacity);
// if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
}
// transform null object into an array
if (is_null())
{
- m_type = value_t::array;
- m_value = value_t::array;
+ m_data.m_type = value_t::array;
+ m_data.m_value = value_t::array;
assert_invariant();
}
// add element to array
- const auto old_capacity = m_value.array->capacity();
- m_value.array->push_back(val);
- set_parent(m_value.array->back(), old_capacity);
+ const auto old_capacity = m_data.m_value.array->capacity();
+ m_data.m_value.array->push_back(val);
+ set_parent(m_data.m_value.array->back(), old_capacity);
}
/// @brief add an object to an array
// transform null object into an object
if (is_null())
{
- m_type = value_t::object;
- m_value = value_t::object;
+ m_data.m_type = value_t::object;
+ m_data.m_value = value_t::object;
assert_invariant();
}
// add element to object
- auto res = m_value.object->insert(val);
+ auto res = m_data.m_value.object->insert(val);
set_parent(res.first->second);
}
// transform null object into an array
if (is_null())
{
- m_type = value_t::array;
- m_value = value_t::array;
+ m_data.m_type = value_t::array;
+ m_data.m_value = value_t::array;
assert_invariant();
}
// add element to array (perfect forwarding)
- const auto old_capacity = m_value.array->capacity();
- m_value.array->emplace_back(std::forward<Args>(args)...);
- return set_parent(m_value.array->back(), old_capacity);
+ const auto old_capacity = m_data.m_value.array->capacity();
+ m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
+ return set_parent(m_data.m_value.array->back(), old_capacity);
}
/// @brief add an object to an object if key does not exist
// transform null object into an object
if (is_null())
{
- m_type = value_t::object;
- m_value = value_t::object;
+ m_data.m_type = value_t::object;
+ m_data.m_value = value_t::object;
assert_invariant();
}
// add element to array (perfect forwarding)
- auto res = m_value.object->emplace(std::forward<Args>(args)...);
+ auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
set_parent(res.first->second);
// create result iterator and set iterator to the result of emplace
iterator insert_iterator(const_iterator pos, Args&& ... args)
{
iterator result(this);
- JSON_ASSERT(m_value.array != nullptr);
+ JSON_ASSERT(m_data.m_value.array != nullptr);
- auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
- m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
- result.m_it.array_iterator = m_value.array->begin() + insert_pos;
+ auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);
+ m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
+ result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;
// This could have been written as:
- // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
+ // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);
// but the return value of insert is missing in GCC 4.8, so it is written this way instead.
set_parents();
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
}
- m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
+ m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
}
/// @brief updates a JSON object from another object, overwriting existing keys
// implicitly convert null value to an empty object
if (is_null())
{
- m_type = value_t::object;
- m_value.object = create<object_t>();
+ m_data.m_type = value_t::object;
+ m_data.m_value.object = create<object_t>();
assert_invariant();
}
{
if (merge_objects && it.value().is_object())
{
- auto it2 = m_value.object->find(it.key());
- if (it2 != m_value.object->end())
+ auto it2 = m_data.m_value.object->find(it.key());
+ if (it2 != m_data.m_value.object->end())
{
it2->second.update(it.value(), true);
continue;
}
}
- m_value.object->operator[](it.key()) = it.value();
+ m_data.m_value.object->operator[](it.key()) = it.value();
#if JSON_DIAGNOSTICS
- m_value.object->operator[](it.key()).m_parent = this;
+ m_data.m_value.object->operator[](it.key()).m_parent = this;
#endif
}
}
void swap(reference other) noexcept (
std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value&&
- std::is_nothrow_move_constructible<json_value>::value&&
+ std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
std::is_nothrow_move_assignable<json_value>::value
)
{
- std::swap(m_type, other.m_type);
- std::swap(m_value, other.m_value);
+ std::swap(m_data.m_type, other.m_data.m_type);
+ std::swap(m_data.m_value, other.m_data.m_value);
set_parents();
other.set_parents();
friend void swap(reference left, reference right) noexcept (
std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value&&
- std::is_nothrow_move_constructible<json_value>::value&&
+ std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
std::is_nothrow_move_assignable<json_value>::value
)
{
/// @brief exchanges the values
/// @sa https://json.nlohmann.me/api/basic_json/swap/
- void swap(array_t& other) // NOLINT(bugprone-exception-escape)
+ void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
{
// swap only works for arrays
if (JSON_HEDLEY_LIKELY(is_array()))
{
using std::swap;
- swap(*(m_value.array), other);
+ swap(*(m_data.m_value.array), other);
}
else
{
/// @brief exchanges the values
/// @sa https://json.nlohmann.me/api/basic_json/swap/
- void swap(object_t& other) // NOLINT(bugprone-exception-escape)
+ void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
{
// swap only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
using std::swap;
- swap(*(m_value.object), other);
+ swap(*(m_data.m_value.object), other);
}
else
{
/// @brief exchanges the values
/// @sa https://json.nlohmann.me/api/basic_json/swap/
- void swap(string_t& other) // NOLINT(bugprone-exception-escape)
+ void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
{
// swap only works for strings
if (JSON_HEDLEY_LIKELY(is_string()))
{
using std::swap;
- swap(*(m_value.string), other);
+ swap(*(m_data.m_value.string), other);
}
else
{
/// @brief exchanges the values
/// @sa https://json.nlohmann.me/api/basic_json/swap/
- void swap(binary_t& other) // NOLINT(bugprone-exception-escape)
+ void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
{
// swap only works for strings
if (JSON_HEDLEY_LIKELY(is_binary()))
{
using std::swap;
- swap(*(m_value.binary), other);
+ swap(*(m_data.m_value.binary), other);
}
else
{
if (JSON_HEDLEY_LIKELY(is_binary()))
{
using std::swap;
- swap(*(m_value.binary), other);
+ swap(*(m_data.m_value.binary), other);
}
else
{
switch (lhs_type) \
{ \
case value_t::array: \
- return (*lhs.m_value.array) op (*rhs.m_value.array); \
+ return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array); \
\
case value_t::object: \
- return (*lhs.m_value.object) op (*rhs.m_value.object); \
+ return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \
\
case value_t::null: \
return (null_result); \
\
case value_t::string: \
- return (*lhs.m_value.string) op (*rhs.m_value.string); \
+ return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \
\
case value_t::boolean: \
- return (lhs.m_value.boolean) op (rhs.m_value.boolean); \
+ return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean); \
\
case value_t::number_integer: \
- return (lhs.m_value.number_integer) op (rhs.m_value.number_integer); \
+ return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer); \
\
case value_t::number_unsigned: \
- return (lhs.m_value.number_unsigned) op (rhs.m_value.number_unsigned); \
+ return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned); \
\
case value_t::number_float: \
- return (lhs.m_value.number_float) op (rhs.m_value.number_float); \
+ return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float); \
\
case value_t::binary: \
- return (*lhs.m_value.binary) op (*rhs.m_value.binary); \
+ return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary); \
\
case value_t::discarded: \
default: \
} \
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
{ \
- return static_cast<number_float_t>(lhs.m_value.number_integer) op rhs.m_value.number_float; \
+ return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \
} \
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
{ \
- return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_integer); \
+ return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \
} \
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
{ \
- return static_cast<number_float_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_float; \
+ return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \
} \
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
{ \
- return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_unsigned); \
+ return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \
} \
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
{ \
- return static_cast<number_integer_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_integer; \
+ return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
} \
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
{ \
- return lhs.m_value.number_integer op static_cast<number_integer_t>(rhs.m_value.number_unsigned); \
+ return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
} \
else if(compares_unordered(lhs, rhs))\
{\
// an operation is computed as an odd number of inverses of others
static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
{
- if ((lhs.is_number_float() && std::isnan(lhs.m_value.number_float) && rhs.is_number())
- || (rhs.is_number_float() && std::isnan(rhs.m_value.number_float) && lhs.is_number()))
+ if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())
+ || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))
{
return true;
}
#endif // JSON_NO_IO
/// @}
-
/////////////////////
// deserialization //
/////////////////////
JSON_HEDLEY_RETURNS_NON_NULL
const char* type_name() const noexcept
{
- switch (m_type)
+ switch (m_data.m_type)
{
case value_t::null:
return "null";
}
}
-
JSON_PRIVATE_UNLESS_TESTED:
//////////////////////
// member variables //
//////////////////////
- /// the type of the current element
- value_t m_type = value_t::null;
+ struct data
+ {
+ /// the type of the current element
+ value_t m_type = value_t::null;
+
+ /// the value of the current element
+ json_value m_value = {};
+
+ data(const value_t v)
+ : m_type(v), m_value(v)
+ {
+ }
+
+ data(size_type cnt, const basic_json& val)
+ : m_type(value_t::array)
+ {
+ m_value.array = create<array_t>(cnt, val);
+ }
+
+ data() noexcept = default;
+ data(data&&) noexcept = default;
+ data(const data&) noexcept = delete;
+ data& operator=(data&&) noexcept = delete;
+ data& operator=(const data&) noexcept = delete;
+
+ ~data() noexcept
+ {
+ m_value.destroy(m_type);
+ }
+ };
- /// the value of the current element
- json_value m_value = {};
+ data m_data = {};
#if JSON_DIAGNOSTICS
/// a pointer to a parent value (for debugging purposes)
return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
}
-
JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
static basic_json from_cbor(detail::span_input_adapter&& i,
return res ? result : basic_json(value_t::discarded);
}
-
/// @brief create a JSON value from an input in BJData format
/// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
template<typename InputType>
}
// make sure the top element of the pointer exists
- json_pointer top_pointer = ptr.top();
+ json_pointer const top_pointer = ptr.top();
if (top_pointer != ptr)
{
result.at(top_pointer);
// parent must exist when performing patch add per RFC6902 specs
basic_json& parent = result.at(ptr);
- switch (parent.m_type)
+ switch (parent.m_data.m_type)
{
case value_t::null:
case value_t::object:
};
// wrapper for "remove" operation; remove value at ptr
- const auto operation_remove = [this, &result](json_pointer & ptr)
+ const auto operation_remove = [this, & result](json_pointer & ptr)
{
// get reference to parent of JSON pointer ptr
const auto last_path = ptr.back();
bool string_type) -> basic_json &
{
// find value
- auto it = val.m_value.object->find(member);
+ auto it = val.m_data.m_value.object->find(member);
// context-sensitive error message
- const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\'');
+ const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\''); // NOLINT(bugprone-unused-local-non-trivial-variable)
// check if desired value is present
- if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end()))
+ if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
{
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
json_pointer from_ptr(from_path);
// the "from" location must exist - use at()
- basic_json v = result.at(from_ptr);
+ basic_json const v = result.at(from_ptr);
// The move operation is functionally identical to a
// "remove" operation on the "from" location, followed
const json_pointer from_ptr(from_path);
// the "from" location must exist - use at()
- basic_json v = result.at(from_ptr);
+ basic_json const v = result.at(from_ptr);
// The copy is functionally identical to an "add"
// operation at the target location using the value
/// @brief user-defined string literal for JSON values
/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
JSON_HEDLEY_NON_NULL(1)
-inline nlohmann::json operator "" _json(const char* s, std::size_t n)
+#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
+ inline nlohmann::json operator ""_json(const char* s, std::size_t n)
+#else
+ inline nlohmann::json operator "" _json(const char* s, std::size_t n)
+#endif
{
return nlohmann::json::parse(s, s + n);
}
/// @brief user-defined string literal for JSON pointer
/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
JSON_HEDLEY_NON_NULL(1)
-inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
+#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
+ inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n)
+#else
+ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
+#endif
{
return nlohmann::json::json_pointer(std::string(s, n));
}
/// @brief hash value for JSON objects
/// @sa https://json.nlohmann.me/api/basic_json/std_hash/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
-struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL>
+struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
{
std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
{
/// @brief exchanges the values of two JSON objects
/// @sa https://json.nlohmann.me/api/basic_json/std_swap/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
-inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)
- is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression)
+inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)
+ is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
{
j1.swap(j2);
} // namespace std
#if JSON_USE_GLOBAL_UDLS
- using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
- using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+ #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
+ using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+ using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+ #else
+ using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+ using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
+ #endif
#endif
// #include <nlohmann/detail/macro_unscope.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
#undef JSON_HAS_THREE_WAY_COMPARISON
#undef JSON_HAS_RANGES
+ #undef JSON_HAS_STATIC_RTTI
#undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#endif
// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
-// | | |__ | | | | | | version 3.11.2
+// | | |__ | | | | | | version 3.11.3
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
-// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
+// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT