Skip to content

Commit bea81e3

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

File tree

1 file changed

+56
-25
lines changed

1 file changed

+56
-25
lines changed

httplib.h

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,28 @@
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+
#endif
169+
148170
/*
149171
* Headers
150172
*/
@@ -2915,7 +2937,8 @@ inline std::string decode_url(const std::string &s,
29152937

29162938
inline std::string file_extension(const std::string &path) {
29172939
std::smatch m;
2918-
static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
2940+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(const std::regex, re,
2941+
("\\.([a-zA-Z0-9]+)$"));
29192942
if (std::regex_search(path, m, re)) { return m[1].str(); }
29202943
return std::string();
29212944
}
@@ -4901,9 +4924,10 @@ class MultipartFormDataParser {
49014924
file_.content_type =
49024925
trim_copy(header.substr(header_content_type.size()));
49034926
} else {
4904-
static const std::regex re_content_disposition(
4905-
R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4906-
std::regex_constants::icase);
4927+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
4928+
const std::regex, re_content_disposition,
4929+
(R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
4930+
std::regex_constants::icase));
49074931

49084932
std::smatch m;
49094933
if (std::regex_match(header, m, re_content_disposition)) {
@@ -4924,8 +4948,9 @@ class MultipartFormDataParser {
49244948
it = params.find("filename*");
49254949
if (it != params.end()) {
49264950
// Only allow UTF-8 encoding...
4927-
static const std::regex re_rfc5987_encoding(
4928-
R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
4951+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
4952+
const std::regex, re_rfc5987_encoding,
4953+
(R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase));
49294954

49304955
std::smatch m2;
49314956
if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
@@ -5092,13 +5117,13 @@ inline std::string random_string(size_t length) {
50925117
// std::random_device might actually be deterministic on some
50935118
// platforms, but due to lack of support in the c++ standard library,
50945119
// 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);
5120+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(std::mt19937, engine, ([]() {
5121+
std::random_device seed_gen;
5122+
std::seed_seq seed_sequence{
5123+
seed_gen(), seed_gen(),
5124+
seed_gen(), seed_gen()};
5125+
return std::mt19937(seed_sequence);
5126+
}()));
51025127

51035128
std::string result;
51045129
for (size_t i = 0; i < length; i++) {
@@ -5612,7 +5637,8 @@ inline bool parse_www_authenticate(const Response &res,
56125637
bool is_proxy) {
56135638
auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
56145639
if (res.has_header(auth_key)) {
5615-
static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
5640+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
5641+
const std::regex, re, (R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"));
56165642
auto s = res.get_header_value(auth_key);
56175643
auto pos = s.find(' ');
56185644
if (pos != std::string::npos) {
@@ -5696,7 +5722,7 @@ inline void hosted_at(const std::string &hostname,
56965722
inline std::string append_query_params(const std::string &path,
56975723
const Params &params) {
56985724
std::string path_with_query = path;
5699-
const static std::regex re("[^?]+\\?.*");
5725+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(const std::regex, re, ("[^?]+\\?.*"));
57005726
auto delm = std::regex_match(path, re) ? '&' : '?';
57015727
path_with_query += delm + detail::params_to_query_str(params);
57025728
return path_with_query;
@@ -5916,7 +5942,7 @@ Result::get_request_header_value_count(const std::string &key) const {
59165942

59175943
// Stream implementation
59185944
inline ssize_t Stream::write(const char *ptr) {
5919-
return write(ptr, strlen(ptr));
5945+
return write(ptr, std::strlen(ptr));
59205946
}
59215947

59225948
inline ssize_t Stream::write(const std::string &s) {
@@ -6470,9 +6496,9 @@ inline bool Server::parse_request_line(const char *s, Request &req) const {
64706496
if (count != 3) { return false; }
64716497
}
64726498

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

64776503
if (methods.find(req.method) == methods.end()) { return false; }
64786504

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

74617487
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
7462-
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
7488+
CPPTHTTPLIB_DEFINE_LOCAL_THREAD_LOCALSTATIC(
7489+
std::regex, re, ("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"));
74637490
#else
7464-
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
7491+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
7492+
const std::regex, re, ("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"));
74657493
#endif
74667494

74677495
std::cmatch m;
@@ -7693,8 +7721,9 @@ inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
76937721
auto location = res.get_header_value("location");
76947722
if (location.empty()) { return false; }
76957723

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

76997728
std::smatch m;
77007729
if (!std::regex_match(location, m, re)) { return false; }
@@ -9787,8 +9816,10 @@ inline Client::Client(const std::string &scheme_host_port)
97879816
inline Client::Client(const std::string &scheme_host_port,
97889817
const std::string &client_cert_path,
97899818
const std::string &client_key_path) {
9790-
const static std::regex re(
9791-
R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
9819+
9820+
CPPHTTPLIB_DEFINE_STATIC_THREAD_LOCAL(
9821+
const std::regex, re,
9822+
(R"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)"));
97929823

97939824
std::smatch m;
97949825
if (std::regex_match(scheme_host_port, m, re)) {

0 commit comments

Comments
 (0)