Skip to content

Commit fd76c2d

Browse files
Add static variable macros
Improve static variable management with thread-local storage and optional no-exit-time destructors.
1 parent 37399af commit fd76c2d

File tree

1 file changed

+55
-25
lines changed

1 file changed

+55
-25
lines changed

httplib.h

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,27 @@
145145
#define CPPHTTPLIB_LISTEN_BACKLOG 5
146146
#endif
147147

148+
#ifndef CPPHTTPLIB_DEFINE_STATIC
149+
#ifdef CPPHTTPLIB_NO_EXIT_TIME_DESTRUCTORS
150+
#define CPPHTTPLIB_DEFINE_STATIC(var_type, var, init) \
151+
static var_type &var = *new typename std::remove_cv<var_type>::type init
152+
#else
153+
#define CPPHTTPLIB_DEFINE_STATIC(var_type, var, init) \
154+
static var_type var = typename std::remove_cv<var_type>::type init
155+
#endif
156+
#endif
157+
158+
#ifndef CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL
159+
#ifdef CPPHTTPLIB_NO_EXIT_TIME_DESTRUCTORS
160+
#define CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(var_type, var, init) \
161+
static thread_local var_type &var = \
162+
*new typename std::remove_cv<var_type>::type init
163+
#else
164+
#define CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(var_type, var, init) \
165+
static thread_local var_type var = \
166+
typename std::remove_cv<var_type>::type init
167+
#endif
168+
148169
/*
149170
* Headers
150171
*/
@@ -2915,7 +2936,8 @@ inline std::string decode_url(const std::string &s,
29152936

29162937
inline std::string file_extension(const std::string &path) {
29172938
std::smatch m;
2918-
static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
2939+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(const std::regex, re,
2940+
("\\.([a-zA-Z0-9]+)$"));
29192941
if (std::regex_search(path, m, re)) { return m[1].str(); }
29202942
return std::string();
29212943
}
@@ -4901,9 +4923,10 @@ class MultipartFormDataParser {
49014923
file_.content_type =
49024924
trim_copy(header.substr(header_content_type.size()));
49034925
} else {
4904-
static const std::regex re_content_disposition(
4905-
R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4906-
std::regex_constants::icase);
4926+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
4927+
const std::regex, re_content_disposition,
4928+
(R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4929+
std::regex_constants::icase));
49074930

49084931
std::smatch m;
49094932
if (std::regex_match(header, m, re_content_disposition)) {
@@ -4924,8 +4947,9 @@ class MultipartFormDataParser {
49244947
it = params.find("filename*");
49254948
if (it != params.end()) {
49264949
// Only allow UTF-8 encoding...
4927-
static const std::regex re_rfc5987_encoding(
4928-
R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
4950+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
4951+
const std::regex, re_rfc5987_encoding,
4952+
(R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase));
49294953

49304954
std::smatch m2;
49314955
if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
@@ -5092,13 +5116,13 @@ inline std::string random_string(size_t length) {
50925116
// std::random_device might actually be deterministic on some
50935117
// platforms, but due to lack of support in the c++ standard library,
50945118
// doing better requires either some ugly hacks or breaking portability.
5095-
static std::random_device seed_gen;
5096-
5097-
// Request 128 bits of entropy for initialization
5098-
static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(),
5099-
seed_gen()};
5100-
5101-
static std::mt19937 engine(seed_sequence);
5119+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(std::mt19937, engine, ([]() {
5120+
std::random_device seed_gen;
5121+
std::seed_seq seed_sequence{
5122+
seed_gen(), seed_gen(),
5123+
seed_gen(), seed_gen()};
5124+
return std::mt19937(seed_sequence);
5125+
}()));
51025126

51035127
std::string result;
51045128
for (size_t i = 0; i < length; i++) {
@@ -5612,7 +5636,8 @@ inline bool parse_www_authenticate(const Response &res,
56125636
bool is_proxy) {
56135637
auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
56145638
if (res.has_header(auth_key)) {
5615-
static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
5639+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
5640+
const std::regex, re, (R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"));
56165641
auto s = res.get_header_value(auth_key);
56175642
auto pos = s.find(' ');
56185643
if (pos != std::string::npos) {
@@ -5696,7 +5721,7 @@ inline void hosted_at(const std::string &hostname,
56965721
inline std::string append_query_params(const std::string &path,
56975722
const Params &params) {
56985723
std::string path_with_query = path;
5699-
const static std::regex re("[^?]+\\?.*");
5724+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(const std::regex, re, ("[^?]+\\?.*"));
57005725
auto delm = std::regex_match(path, re) ? '&' : '?';
57015726
path_with_query += delm + detail::params_to_query_str(params);
57025727
return path_with_query;
@@ -5916,7 +5941,7 @@ Result::get_request_header_value_count(const std::string &key) const {
59165941

59175942
// Stream implementation
59185943
inline ssize_t Stream::write(const char *ptr) {
5919-
return write(ptr, strlen(ptr));
5944+
return write(ptr, std::strlen(ptr));
59205945
}
59215946

59225947
inline ssize_t Stream::write(const std::string &s) {
@@ -6470,9 +6495,9 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {
64706495
if (count != 3) { return false; }
64716496
}
64726497

6473-
static const std::set<std::string> methods{
6474-
"GET", "HEAD", "POST", "PUT", "DELETE",
6475-
"CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"};
6498+
CPPHTTPLIB_DEFINE_STATIC(std::set<std::string>, methods,
6499+
({"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT",
6500+
"OPTIONS", "TRACE", "PATCH", "PRI"}));
64766501

64776502
if (methods.find(req.method) == methods.end()) { return false; }
64786503

@@ -7459,9 +7484,11 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
74597484
if (!line_reader.getline()) { return false; }
74607485

74617486
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
7462-
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
7487+
CPPTHTTPLIB_DEFINE_LOCAL_THREAD_LOCALSTATIC(
7488+
std::regex, re, ("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"));
74637489
#else
7464-
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
7490+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
7491+
const std::regex, re, ("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"));
74657492
#endif
74667493

74677494
std::cmatch m;
@@ -7693,8 +7720,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
76937720
auto location = res.get_header_value("location");
76947721
if (location.empty()) { return false; }
76957722

7696-
const static std::regex re(
7697-
R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
7723+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
7724+
const std::regex, re,
7725+
(R"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"));
76987726

76997727
std::smatch m;
77007728
if (!std::regex_match(location, m, re)) { return false; }
@@ -9787,8 +9815,10 @@ inline Client::Client(const std::string &scheme_host_port)
97879815
inline Client::Client(const std::string &scheme_host_port,
97889816
const std::string &client_cert_path,
97899817
const std::string &client_key_path) {
9790-
const static std::regex re(
9791-
R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
9818+
9819+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
9820+
const std::regex, re,
9821+
(R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)"));
97929822

97939823
std::smatch m;
97949824
if (std::regex_match(scheme_host_port, m, re)) {

0 commit comments

Comments
 (0)