Added noexcept

This commit is contained in:
eidheim 2017-07-22 12:50:40 +02:00
commit 7dd2d2108a
8 changed files with 122 additions and 112 deletions

View file

@ -40,19 +40,24 @@ namespace SimpleWeb {
friend class ClientBase<socket_type>; friend class ClientBase<socket_type>;
public: public:
size_t size() { size_t size() noexcept {
return streambuf.size(); return streambuf.size();
} }
/// Convenience function to return std::string. Note that the stream buffer is emptied when this functions is used. /// Convenience function to return std::string. Note that the stream buffer is emptied when this functions is used.
std::string string() { std::string string() noexcept {
try {
std::stringstream ss; std::stringstream ss;
ss << rdbuf(); ss << rdbuf();
return ss.str(); return ss.str();
} }
catch(...) {
return std::string();
}
}
private: private:
asio::streambuf &streambuf; asio::streambuf &streambuf;
Content(asio::streambuf &streambuf) : std::istream(&streambuf), streambuf(streambuf) {} Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {}
}; };
class Response { class Response {
@ -69,14 +74,14 @@ namespace SimpleWeb {
private: private:
asio::streambuf content_buffer; asio::streambuf content_buffer;
Response() : content(content_buffer) {} Response() noexcept : content(content_buffer) {}
}; };
class Config { class Config {
friend class ClientBase<socket_type>; friend class ClientBase<socket_type>;
private: private:
Config() {} Config() noexcept {}
public: public:
/// Set timeout on requests in seconds. Default value: 0 (no timeout). /// Set timeout on requests in seconds. Default value: 0 (no timeout).
@ -91,7 +96,7 @@ namespace SimpleWeb {
class Connection : public std::enable_shared_from_this<Connection> { class Connection : public std::enable_shared_from_this<Connection> {
public: public:
template <typename... Args> template <typename... Args>
Connection(std::shared_ptr<ScopeRunner> handler_runner, long timeout, Args &&... args) Connection(std::shared_ptr<ScopeRunner> handler_runner, long timeout, Args &&... args) noexcept
: handler_runner(std::move(handler_runner)), timeout(timeout), socket(new socket_type(std::forward<Args>(args)...)) {} : handler_runner(std::move(handler_runner)), timeout(timeout), socket(new socket_type(std::forward<Args>(args)...)) {}
std::shared_ptr<ScopeRunner> handler_runner; std::shared_ptr<ScopeRunner> handler_runner;
@ -103,7 +108,7 @@ namespace SimpleWeb {
std::unique_ptr<asio::deadline_timer> timer; std::unique_ptr<asio::deadline_timer> timer;
void set_timeout(long seconds = 0) { void set_timeout(long seconds = 0) noexcept {
if(seconds == 0) if(seconds == 0)
seconds = timeout; seconds = timeout;
if(seconds == 0) { if(seconds == 0) {
@ -121,7 +126,7 @@ namespace SimpleWeb {
}); });
} }
void cancel_timeout() { void cancel_timeout() noexcept {
if(timer) if(timer)
timer->cancel(); timer->cancel();
} }
@ -129,7 +134,7 @@ namespace SimpleWeb {
class Session { class Session {
public: public:
Session(std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_buffer) Session(std::shared_ptr<Connection> connection, std::unique_ptr<asio::streambuf> request_buffer) noexcept
: connection(std::move(connection)), request_buffer(std::move(request_buffer)), response(new Response()) {} : connection(std::move(connection)), request_buffer(std::move(request_buffer)), response(new Response()) {}
std::shared_ptr<Connection> connection; std::shared_ptr<Connection> connection;
@ -209,7 +214,7 @@ namespace SimpleWeb {
/// Asynchronous request where setting and/or running Client's io_service is required. /// Asynchronous request where setting and/or running Client's io_service is required.
/// Do not use concurrently with the synchronous request functions. /// Do not use concurrently with the synchronous request functions.
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header, void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) { std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) noexcept {
auto session = std::make_shared<Session>(get_connection(), create_request_header(method, path, header)); auto session = std::make_shared<Session>(get_connection(), create_request_header(method, path, header));
auto response = session->response; auto response = session->response;
auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_)); auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_));
@ -251,24 +256,24 @@ namespace SimpleWeb {
/// Asynchronous request where setting and/or running Client's io_service is required. /// Asynchronous request where setting and/or running Client's io_service is required.
/// Do not use concurrently with the synchronous request functions. /// Do not use concurrently with the synchronous request functions.
void request(const std::string &method, const std::string &path, string_view content, void request(const std::string &method, const std::string &path, string_view content,
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) { std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
} }
/// Asynchronous request where setting and/or running Client's io_service is required. /// Asynchronous request where setting and/or running Client's io_service is required.
void request(const std::string &method, const std::string &path, void request(const std::string &method, const std::string &path,
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) { std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback)); request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
} }
/// Asynchronous request where setting and/or running Client's io_service is required. /// Asynchronous request where setting and/or running Client's io_service is required.
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) { void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback)); request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
} }
/// Asynchronous request where setting and/or running Client's io_service is required. /// Asynchronous request where setting and/or running Client's io_service is required.
void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header, void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header,
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) { std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) noexcept {
auto session = std::make_shared<Session>(get_connection(), create_request_header(method, path, header)); auto session = std::make_shared<Session>(get_connection(), create_request_header(method, path, header));
auto response = session->response; auto response = session->response;
auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_)); auto request_callback = std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code &)>>(std::move(request_callback_));
@ -313,12 +318,12 @@ namespace SimpleWeb {
/// Asynchronous request where setting and/or running Client's io_service is required. /// Asynchronous request where setting and/or running Client's io_service is required.
void request(const std::string &method, const std::string &path, std::istream &content, void request(const std::string &method, const std::string &path, std::istream &content,
std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) { std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback) noexcept {
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback)); request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
} }
/// Close connections /// Close connections
void stop() { void stop() noexcept {
std::unique_lock<std::mutex> lock(connections_mutex); std::unique_lock<std::mutex> lock(connections_mutex);
for(auto it = connections.begin(); it != connections.end();) { for(auto it = connections.begin(); it != connections.end();) {
error_code ec; error_code ec;
@ -327,7 +332,7 @@ namespace SimpleWeb {
} }
} }
virtual ~ClientBase() { virtual ~ClientBase() noexcept {
handler_runner->stop(); handler_runner->stop();
stop(); stop();
} }
@ -348,13 +353,13 @@ namespace SimpleWeb {
size_t concurrent_synchronous_requests = 0; size_t concurrent_synchronous_requests = 0;
std::mutex concurrent_synchronous_requests_mutex; std::mutex concurrent_synchronous_requests_mutex;
ClientBase(const std::string &host_port, unsigned short default_port) : handler_runner(new ScopeRunner()) { ClientBase(const std::string &host_port, unsigned short default_port) noexcept : handler_runner(new ScopeRunner()) {
auto parsed_host_port = parse_host_port(host_port, default_port); auto parsed_host_port = parse_host_port(host_port, default_port);
host = parsed_host_port.first; host = parsed_host_port.first;
port = parsed_host_port.second; port = parsed_host_port.second;
} }
std::shared_ptr<Connection> get_connection() { std::shared_ptr<Connection> get_connection() noexcept {
std::shared_ptr<Connection> connection; std::shared_ptr<Connection> connection;
std::unique_lock<std::mutex> lock(connections_mutex); std::unique_lock<std::mutex> lock(connections_mutex);
@ -388,10 +393,10 @@ namespace SimpleWeb {
return connection; return connection;
} }
virtual std::shared_ptr<Connection> create_connection() = 0; virtual std::shared_ptr<Connection> create_connection() noexcept = 0;
virtual void connect(const std::shared_ptr<Session> &) = 0; virtual void connect(const std::shared_ptr<Session> &) noexcept = 0;
std::unique_ptr<asio::streambuf> create_request_header(const std::string &method, const std::string &path, const CaseInsensitiveMultimap &header) const { std::unique_ptr<asio::streambuf> create_request_header(const std::string &method, const std::string &path, const CaseInsensitiveMultimap &header) const noexcept {
auto corrected_path = path; auto corrected_path = path;
if(corrected_path == "") if(corrected_path == "")
corrected_path = "/"; corrected_path = "/";
@ -407,7 +412,7 @@ namespace SimpleWeb {
return request_buffer; return request_buffer;
} }
std::pair<std::string, unsigned short> parse_host_port(const std::string &host_port, unsigned short default_port) const { std::pair<std::string, unsigned short> parse_host_port(const std::string &host_port, unsigned short default_port) const noexcept {
std::pair<std::string, unsigned short> parsed_host_port; std::pair<std::string, unsigned short> parsed_host_port;
size_t host_end = host_port.find(':'); size_t host_end = host_port.find(':');
if(host_end == std::string::npos) { if(host_end == std::string::npos) {
@ -421,7 +426,7 @@ namespace SimpleWeb {
return parsed_host_port; return parsed_host_port;
} }
void write(const std::shared_ptr<Session> &session) { void write(const std::shared_ptr<Session> &session) noexcept {
session->connection->set_timeout(); session->connection->set_timeout();
asio::async_write(*session->connection->socket, session->request_buffer->data(), [this, session](const error_code &ec, size_t /*bytes_transferred*/) { asio::async_write(*session->connection->socket, session->request_buffer->data(), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
session->connection->cancel_timeout(); session->connection->cancel_timeout();
@ -435,7 +440,7 @@ namespace SimpleWeb {
}); });
} }
void read(const std::shared_ptr<Session> &session) { void read(const std::shared_ptr<Session> &session) noexcept {
session->connection->set_timeout(); session->connection->set_timeout();
asio::async_read_until(*session->connection->socket, session->response->content_buffer, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) { asio::async_read_until(*session->connection->socket, session->response->content_buffer, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
session->connection->cancel_timeout(); session->connection->cancel_timeout();
@ -515,7 +520,7 @@ namespace SimpleWeb {
}); });
} }
void read_chunked(const std::shared_ptr<Session> &session, const std::shared_ptr<asio::streambuf> &tmp_streambuf) { void read_chunked(const std::shared_ptr<Session> &session, const std::shared_ptr<asio::streambuf> &tmp_streambuf) noexcept {
session->connection->set_timeout(); session->connection->set_timeout();
asio::async_read_until(*session->connection->socket, session->response->content_buffer, "\r\n", [this, session, tmp_streambuf](const error_code &ec, size_t bytes_transferred) { asio::async_read_until(*session->connection->socket, session->response->content_buffer, "\r\n", [this, session, tmp_streambuf](const error_code &ec, size_t bytes_transferred) {
session->connection->cancel_timeout(); session->connection->cancel_timeout();
@ -583,14 +588,14 @@ namespace SimpleWeb {
template <> template <>
class Client<HTTP> : public ClientBase<HTTP> { class Client<HTTP> : public ClientBase<HTTP> {
public: public:
Client(const std::string &server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {} Client(const std::string &server_port_path) noexcept : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
protected: protected:
std::shared_ptr<Connection> create_connection() override { std::shared_ptr<Connection> create_connection() noexcept override {
return std::make_shared<Connection>(handler_runner, config.timeout, *io_service); return std::make_shared<Connection>(handler_runner, config.timeout, *io_service);
} }
void connect(const std::shared_ptr<Session> &session) override { void connect(const std::shared_ptr<Session> &session) noexcept override {
if(!session->connection->socket->lowest_layer().is_open()) { if(!session->connection->socket->lowest_layer().is_open()) {
auto resolver = std::make_shared<asio::ip::tcp::resolver>(*io_service); auto resolver = std::make_shared<asio::ip::tcp::resolver>(*io_service);
session->connection->set_timeout(config.timeout_connect); session->connection->set_timeout(config.timeout_connect);

View file

@ -16,7 +16,7 @@ namespace SimpleWeb {
class Client<HTTPS> : public ClientBase<HTTPS> { class Client<HTTPS> : public ClientBase<HTTPS> {
public: public:
Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &cert_file = std::string(), Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &cert_file = std::string(),
const std::string &private_key_file = std::string(), const std::string &verify_file = std::string()) const std::string &private_key_file = std::string(), const std::string &verify_file = std::string()) noexcept
: ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) { : ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) {
if(cert_file.size() > 0 && private_key_file.size() > 0) { if(cert_file.size() > 0 && private_key_file.size() > 0) {
context.use_certificate_chain_file(cert_file); context.use_certificate_chain_file(cert_file);
@ -40,11 +40,11 @@ namespace SimpleWeb {
protected: protected:
asio::ssl::context context; asio::ssl::context context;
std::shared_ptr<Connection> create_connection() override { std::shared_ptr<Connection> create_connection() noexcept override {
return std::make_shared<Connection>(handler_runner, config.timeout, *io_service, context); return std::make_shared<Connection>(handler_runner, config.timeout, *io_service, context);
} }
void connect(const std::shared_ptr<Session> &session) override { void connect(const std::shared_ptr<Session> &session) noexcept override {
if(!session->connection->socket->lowest_layer().is_open()) { if(!session->connection->socket->lowest_layer().is_open()) {
auto resolver = std::make_shared<asio::ip::tcp::resolver>(*io_service); auto resolver = std::make_shared<asio::ip::tcp::resolver>(*io_service);
resolver->async_resolve(*query, [this, session, resolver](const error_code &ec, asio::ip::tcp::resolver::iterator it) { resolver->async_resolve(*query, [this, session, resolver](const error_code &ec, asio::ip::tcp::resolver::iterator it) {
@ -116,7 +116,7 @@ namespace SimpleWeb {
write(session); write(session);
} }
void handshake(const std::shared_ptr<Session> &session) { void handshake(const std::shared_ptr<Session> &session) noexcept {
session->connection->set_timeout(this->config.timeout_connect); session->connection->set_timeout(this->config.timeout_connect);
session->connection->socket->async_handshake(asio::ssl::stream_base::client, [this, session](const error_code &ec) { session->connection->socket->async_handshake(asio::ssl::stream_base::client, [this, session](const error_code &ec) {
session->connection->cancel_timeout(); session->connection->cancel_timeout();

View file

@ -16,7 +16,7 @@
namespace SimpleWeb { namespace SimpleWeb {
// TODO 2017: remove workaround for MSVS 2012 // TODO 2017: remove workaround for MSVS 2012
#if _MSC_VER == 1700 // MSVS 2012 has no definition for round() #if _MSC_VER == 1700 // MSVS 2012 has no definition for round()
inline double round(double x) { // Custom definition of round() for positive numbers inline double round(double x) noexcept { // Custom definition of round() for positive numbers
return floor(x + 0.5); return floor(x + 0.5);
} }
#endif #endif
@ -27,7 +27,7 @@ namespace SimpleWeb {
public: public:
class Base64 { class Base64 {
public: public:
static std::string encode(const std::string &ascii) { static std::string encode(const std::string &ascii) noexcept {
std::string base64; std::string base64;
BIO *bio, *b64; BIO *bio, *b64;
@ -59,7 +59,7 @@ namespace SimpleWeb {
return base64; return base64;
} }
static std::string decode(const std::string &base64) { static std::string decode(const std::string &base64) noexcept {
std::string ascii; std::string ascii;
// Resize ascii, however, the size is a up to two bytes too large. // Resize ascii, however, the size is a up to two bytes too large.
@ -84,7 +84,7 @@ namespace SimpleWeb {
}; };
/// Return hex string from bytes in input string. /// Return hex string from bytes in input string.
static std::string to_hex_string(const std::string &input) { static std::string to_hex_string(const std::string &input) noexcept {
std::stringstream hex_stream; std::stringstream hex_stream;
hex_stream << std::hex << std::internal << std::setfill('0'); hex_stream << std::hex << std::internal << std::setfill('0');
for(auto &byte : input) for(auto &byte : input)
@ -92,7 +92,7 @@ namespace SimpleWeb {
return hex_stream.str(); return hex_stream.str();
} }
static std::string md5(const std::string &input, size_t iterations = 1) { static std::string md5(const std::string &input, size_t iterations = 1) noexcept {
std::string hash; std::string hash;
hash.resize(128 / 8); hash.resize(128 / 8);
@ -104,7 +104,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string md5(std::istream &stream, size_t iterations = 1) { static std::string md5(std::istream &stream, size_t iterations = 1) noexcept {
MD5_CTX context; MD5_CTX context;
MD5_Init(&context); MD5_Init(&context);
std::streamsize read_length; std::streamsize read_length;
@ -121,7 +121,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string sha1(const std::string &input, size_t iterations = 1) { static std::string sha1(const std::string &input, size_t iterations = 1) noexcept {
std::string hash; std::string hash;
hash.resize(160 / 8); hash.resize(160 / 8);
@ -133,7 +133,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string sha1(std::istream &stream, size_t iterations = 1) { static std::string sha1(std::istream &stream, size_t iterations = 1) noexcept {
SHA_CTX context; SHA_CTX context;
SHA1_Init(&context); SHA1_Init(&context);
std::streamsize read_length; std::streamsize read_length;
@ -150,7 +150,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string sha256(const std::string &input, size_t iterations = 1) { static std::string sha256(const std::string &input, size_t iterations = 1) noexcept {
std::string hash; std::string hash;
hash.resize(256 / 8); hash.resize(256 / 8);
@ -162,7 +162,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string sha256(std::istream &stream, size_t iterations = 1) { static std::string sha256(std::istream &stream, size_t iterations = 1) noexcept {
SHA256_CTX context; SHA256_CTX context;
SHA256_Init(&context); SHA256_Init(&context);
std::streamsize read_length; std::streamsize read_length;
@ -179,7 +179,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string sha512(const std::string &input, size_t iterations = 1) { static std::string sha512(const std::string &input, size_t iterations = 1) noexcept {
std::string hash; std::string hash;
hash.resize(512 / 8); hash.resize(512 / 8);
@ -191,7 +191,7 @@ namespace SimpleWeb {
return hash; return hash;
} }
static std::string sha512(std::istream &stream, size_t iterations = 1) { static std::string sha512(std::istream &stream, size_t iterations = 1) noexcept {
SHA512_CTX context; SHA512_CTX context;
SHA512_Init(&context); SHA512_Init(&context);
std::streamsize read_length; std::streamsize read_length;
@ -209,7 +209,7 @@ namespace SimpleWeb {
} }
/// key_size is number of bytes of the returned key. /// key_size is number of bytes of the returned key.
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) { static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept {
std::string key; std::string key;
key.resize(key_size); key.resize(key_size);
PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(), PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),

View file

@ -59,10 +59,10 @@ namespace SimpleWeb {
std::shared_ptr<Session> session; std::shared_ptr<Session> session;
long timeout_content; long timeout_content;
Response(std::shared_ptr<Session> session, long timeout_content) : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {} Response(std::shared_ptr<Session> session, long timeout_content) noexcept : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {}
template <typename size_type> template <typename size_type>
void write_header(const CaseInsensitiveMultimap &header, size_type size) { void write_header(const CaseInsensitiveMultimap &header, size_type size) noexcept {
bool content_length_written = false; bool content_length_written = false;
bool chunked_transfer_encoding = false; bool chunked_transfer_encoding = false;
for(auto &field : header) { for(auto &field : header) {
@ -80,12 +80,12 @@ namespace SimpleWeb {
} }
public: public:
size_t size() { size_t size() noexcept {
return streambuf.size(); return streambuf.size();
} }
/// Use this function if you need to recursively send parts of a longer message /// Use this function if you need to recursively send parts of a longer message
void send(const std::function<void(const error_code &)> &callback = nullptr) { void send(const std::function<void(const error_code &)> &callback = nullptr) noexcept {
session->connection->set_timeout(timeout_content); session->connection->set_timeout(timeout_content);
auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, size_t /*bytes_transferred*/) { asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, size_t /*bytes_transferred*/) {
@ -99,18 +99,18 @@ namespace SimpleWeb {
} }
/// Write directly to stream buffer using std::ostream::write /// Write directly to stream buffer using std::ostream::write
void write(const char_type *ptr, std::streamsize n) { void write(const char_type *ptr, std::streamsize n) noexcept {
std::ostream::write(ptr, n); std::ostream::write(ptr, n);
} }
/// Convenience function for writing status line, potential header fields, and empty content /// Convenience function for writing status line, potential header fields, and empty content
void write(StatusCode status_code = StatusCode::success_ok, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) { void write(StatusCode status_code = StatusCode::success_ok, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n"; *this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
write_header(header, 0); write_header(header, 0);
} }
/// Convenience function for writing status line, header fields, and content /// Convenience function for writing status line, header fields, and content
void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) { void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n"; *this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
write_header(header, content.size()); write_header(header, content.size());
if(!content.empty()) if(!content.empty())
@ -118,7 +118,7 @@ namespace SimpleWeb {
} }
/// Convenience function for writing status line, header fields, and content /// Convenience function for writing status line, header fields, and content
void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) { void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n"; *this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
content.seekg(0, std::ios::end); content.seekg(0, std::ios::end);
auto size = content.tellg(); auto size = content.tellg();
@ -129,17 +129,17 @@ namespace SimpleWeb {
} }
/// Convenience function for writing success status line, header fields, and content /// Convenience function for writing success status line, header fields, and content
void write(const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) { void write(const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
write(StatusCode::success_ok, content, header); write(StatusCode::success_ok, content, header);
} }
/// Convenience function for writing success status line, header fields, and content /// Convenience function for writing success status line, header fields, and content
void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) { void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) noexcept {
write(StatusCode::success_ok, content, header); write(StatusCode::success_ok, content, header);
} }
/// Convenience function for writing success status line, and header fields /// Convenience function for writing success status line, and header fields
void write(const CaseInsensitiveMultimap &header) { void write(const CaseInsensitiveMultimap &header) noexcept {
write(StatusCode::success_ok, std::string(), header); write(StatusCode::success_ok, std::string(), header);
} }
@ -154,19 +154,24 @@ namespace SimpleWeb {
friend class ServerBase<socket_type>; friend class ServerBase<socket_type>;
public: public:
size_t size() { size_t size() noexcept {
return streambuf.size(); return streambuf.size();
} }
/// Convenience function to return std::string. Note that the stream buffer is emptied when this functions is used. /// Convenience function to return std::string. Note that the stream buffer is emptied when this functions is used.
std::string string() { std::string string() noexcept {
try {
std::stringstream ss; std::stringstream ss;
ss << rdbuf(); ss << rdbuf();
return ss.str(); return ss.str();
} }
catch(...) {
return std::string();
}
}
private: private:
asio::streambuf &streambuf; asio::streambuf &streambuf;
Content(asio::streambuf &streambuf) : std::istream(&streambuf), streambuf(streambuf) {} Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {}
}; };
class Request { class Request {
@ -187,14 +192,14 @@ namespace SimpleWeb {
unsigned short remote_endpoint_port; unsigned short remote_endpoint_port;
/// Returns query keys with percent-decoded values. /// Returns query keys with percent-decoded values.
CaseInsensitiveMultimap parse_query_string() { CaseInsensitiveMultimap parse_query_string() noexcept {
return SimpleWeb::QueryString::parse(query_string); return SimpleWeb::QueryString::parse(query_string);
} }
private: private:
asio::streambuf streambuf; asio::streambuf streambuf;
Request(const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) Request(const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
: content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {} : content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {}
}; };
@ -202,7 +207,7 @@ namespace SimpleWeb {
class Connection : public std::enable_shared_from_this<Connection> { class Connection : public std::enable_shared_from_this<Connection> {
public: public:
template <typename... Args> template <typename... Args>
Connection(std::shared_ptr<ScopeRunner> handler_runner, Args &&... args) : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward<Args>(args)...)) {} Connection(std::shared_ptr<ScopeRunner> handler_runner, Args &&... args) noexcept : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward<Args>(args)...)) {}
std::shared_ptr<ScopeRunner> handler_runner; std::shared_ptr<ScopeRunner> handler_runner;
@ -211,14 +216,14 @@ namespace SimpleWeb {
std::unique_ptr<asio::deadline_timer> timer; std::unique_ptr<asio::deadline_timer> timer;
void close() { void close() noexcept {
error_code ec; error_code ec;
std::unique_lock<std::mutex> lock(socket_close_mutex); // The following operations seems to be needed to run sequentially std::unique_lock<std::mutex> lock(socket_close_mutex); // The following operations seems to be needed to run sequentially
socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec); socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
socket->lowest_layer().close(ec); socket->lowest_layer().close(ec);
} }
void set_timeout(long seconds) { void set_timeout(long seconds) noexcept {
if(seconds == 0) { if(seconds == 0) {
timer = nullptr; timer = nullptr;
return; return;
@ -233,7 +238,7 @@ namespace SimpleWeb {
}); });
} }
void cancel_timeout() { void cancel_timeout() noexcept {
if(timer) if(timer)
timer->cancel(); timer->cancel();
} }
@ -241,7 +246,7 @@ namespace SimpleWeb {
class Session { class Session {
public: public:
Session(std::shared_ptr<Connection> connection) : connection(std::move(connection)) { Session(std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
try { try {
auto remote_endpoint = this->connection->socket->lowest_layer().remote_endpoint(); auto remote_endpoint = this->connection->socket->lowest_layer().remote_endpoint();
request = std::shared_ptr<Request>(new Request(remote_endpoint.address().to_string(), remote_endpoint.port())); request = std::shared_ptr<Request>(new Request(remote_endpoint.address().to_string(), remote_endpoint.port()));
@ -259,7 +264,7 @@ namespace SimpleWeb {
class Config { class Config {
friend class ServerBase<socket_type>; friend class ServerBase<socket_type>;
Config(unsigned short port) : port(port) {} Config(unsigned short port) noexcept : port(port) {}
public: public:
/// Port number to use. Defaults to 80 for HTTP and 443 for HTTPS. /// Port number to use. Defaults to 80 for HTTP and 443 for HTTPS.
@ -287,7 +292,7 @@ namespace SimpleWeb {
public: public:
regex_orderable(const char *regex_cstr) : regex::regex(regex_cstr), str(regex_cstr) {} regex_orderable(const char *regex_cstr) : regex::regex(regex_cstr), str(regex_cstr) {}
regex_orderable(std::string regex_str) : regex::regex(regex_str), str(std::move(regex_str)) {} regex_orderable(std::string regex_str) : regex::regex(regex_str), str(std::move(regex_str)) {}
bool operator<(const regex_orderable &rhs) const { bool operator<(const regex_orderable &rhs) const noexcept {
return str < rhs.str; return str < rhs.str;
} }
}; };
@ -305,7 +310,7 @@ namespace SimpleWeb {
/// If you have your own asio::io_service, store its pointer here before running start(). /// If you have your own asio::io_service, store its pointer here before running start().
std::shared_ptr<asio::io_service> io_service; std::shared_ptr<asio::io_service> io_service;
virtual void start() { virtual void start() noexcept {
if(!io_service) { if(!io_service) {
io_service = std::make_shared<asio::io_service>(); io_service = std::make_shared<asio::io_service>();
internal_io_service = true; internal_io_service = true;
@ -349,7 +354,7 @@ namespace SimpleWeb {
} }
/// Stop accepting new requests, and close current connections. /// Stop accepting new requests, and close current connections.
void stop() { void stop() noexcept {
if(acceptor) { if(acceptor) {
error_code ec; error_code ec;
acceptor->close(ec); acceptor->close(ec);
@ -366,7 +371,7 @@ namespace SimpleWeb {
} }
} }
virtual ~ServerBase() { virtual ~ServerBase() noexcept {
handler_runner->stop(); handler_runner->stop();
stop(); stop();
} }
@ -382,12 +387,12 @@ namespace SimpleWeb {
std::shared_ptr<ScopeRunner> handler_runner; std::shared_ptr<ScopeRunner> handler_runner;
ServerBase(unsigned short port) : config(port), connections(new std::unordered_set<Connection *>()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {} ServerBase(unsigned short port) noexcept : config(port), connections(new std::unordered_set<Connection *>()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {}
virtual void accept() = 0; virtual void accept() noexcept = 0;
template <typename... Args> template <typename... Args>
std::shared_ptr<Connection> create_connection(Args &&... args) { std::shared_ptr<Connection> create_connection(Args &&... args) noexcept {
auto connections = this->connections; auto connections = this->connections;
auto connections_mutex = this->connections_mutex; auto connections_mutex = this->connections_mutex;
auto connection = std::shared_ptr<Connection>(new Connection(handler_runner, std::forward<Args>(args)...), [connections, connections_mutex](Connection *connection) { auto connection = std::shared_ptr<Connection>(new Connection(handler_runner, std::forward<Args>(args)...), [connections, connections_mutex](Connection *connection) {
@ -406,7 +411,7 @@ namespace SimpleWeb {
return connection; return connection;
} }
void read_request_and_content(const std::shared_ptr<Session> &session) { void read_request_and_content(const std::shared_ptr<Session> &session) noexcept {
session->connection->set_timeout(config.timeout_request); session->connection->set_timeout(config.timeout_request);
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) { asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
session->connection->cancel_timeout(); session->connection->cancel_timeout();
@ -463,7 +468,7 @@ namespace SimpleWeb {
}); });
} }
void find_resource(const std::shared_ptr<Session> &session) { void find_resource(const std::shared_ptr<Session> &session) noexcept {
// Upgrade connection // Upgrade connection
if(on_upgrade) { if(on_upgrade) {
auto it = session->request->header.find("Upgrade"); auto it = session->request->header.find("Upgrade");
@ -498,7 +503,7 @@ namespace SimpleWeb {
} }
void write_response(const std::shared_ptr<Session> &session, void write_response(const std::shared_ptr<Session> &session,
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> &resource_function) { std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> &resource_function) noexcept {
session->connection->set_timeout(config.timeout_content); session->connection->set_timeout(config.timeout_content);
auto response = std::shared_ptr<Response>(new Response(session, config.timeout_content), [this](Response *response_ptr) { auto response = std::shared_ptr<Response>(new Response(session, config.timeout_content), [this](Response *response_ptr) {
auto response = std::shared_ptr<Response>(response_ptr); auto response = std::shared_ptr<Response>(response_ptr);
@ -547,10 +552,10 @@ namespace SimpleWeb {
template <> template <>
class Server<HTTP> : public ServerBase<HTTP> { class Server<HTTP> : public ServerBase<HTTP> {
public: public:
Server() : ServerBase<HTTP>::ServerBase(80) {} Server() noexcept : ServerBase<HTTP>::ServerBase(80) {}
protected: protected:
void accept() override { void accept() noexcept override {
auto session = std::make_shared<Session>(create_connection(*io_service)); auto session = std::make_shared<Session>(create_connection(*io_service));
acceptor->async_accept(*session->connection->socket, [this, session](const error_code &ec) { acceptor->async_accept(*session->connection->socket, [this, session](const error_code &ec) {

View file

@ -21,7 +21,7 @@ namespace SimpleWeb {
bool set_session_id_context = false; bool set_session_id_context = false;
public: public:
Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string()) Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string()) noexcept
: ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) { : ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) {
context.use_certificate_chain_file(cert_file); context.use_certificate_chain_file(cert_file);
context.use_private_key_file(private_key_file, asio::ssl::context::pem); context.use_private_key_file(private_key_file, asio::ssl::context::pem);
@ -33,7 +33,7 @@ namespace SimpleWeb {
} }
} }
void start() override { void start() noexcept override {
if(set_session_id_context) { if(set_session_id_context) {
// Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH // Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH
session_id_context = std::to_string(config.port) + ':'; session_id_context = std::to_string(config.port) + ':';
@ -47,7 +47,7 @@ namespace SimpleWeb {
protected: protected:
asio::ssl::context context; asio::ssl::context context;
void accept() override { void accept() noexcept override {
auto session = std::make_shared<Session>(create_connection(*io_service, context)); auto session = std::make_shared<Session>(create_connection(*io_service, context));
acceptor->async_accept(session->connection->socket->lowest_layer(), [this, session](const error_code &ec) { acceptor->async_accept(session->connection->socket->lowest_layer(), [this, session](const error_code &ec) {

View file

@ -70,7 +70,7 @@ namespace SimpleWeb {
server_error_network_authentication_required server_error_network_authentication_required
}; };
const static std::vector<std::pair<StatusCode, std::string>> &status_codes() { const static std::vector<std::pair<StatusCode, std::string>> &status_codes() noexcept {
const static std::vector<std::pair<StatusCode, std::string>> status_codes = { const static std::vector<std::pair<StatusCode, std::string>> status_codes = {
{StatusCode::unknown, ""}, {StatusCode::unknown, ""},
{StatusCode::information_continue, "100 Continue"}, {StatusCode::information_continue, "100 Continue"},
@ -137,7 +137,7 @@ namespace SimpleWeb {
return status_codes; return status_codes;
} }
inline StatusCode status_code(const std::string &status_code_str) { inline StatusCode status_code(const std::string &status_code_str) noexcept {
for(auto &status_code : status_codes()) { for(auto &status_code : status_codes()) {
if(status_code.second == status_code_str) if(status_code.second == status_code_str)
return status_code.first; return status_code.first;
@ -145,7 +145,7 @@ namespace SimpleWeb {
return StatusCode::unknown; return StatusCode::unknown;
} }
inline const std::string &status_code(StatusCode status_code_enum) { inline const std::string &status_code(StatusCode status_code_enum) noexcept {
for(auto &status_code : status_codes()) { for(auto &status_code : status_codes()) {
if(status_code.first == status_code_enum) if(status_code.first == status_code_enum)
return status_code.second; return status_code.second;

View file

@ -10,7 +10,7 @@ class ServerTest : public ServerBase<HTTP> {
public: public:
ServerTest() : ServerBase<HTTP>::ServerBase(8080) {} ServerTest() : ServerBase<HTTP>::ServerBase(8080) {}
void accept() override {} void accept() noexcept override {}
void parse_request_test() { void parse_request_test() {
auto session = std::make_shared<Session>(create_connection(*io_service)); auto session = std::make_shared<Session>(create_connection(*io_service));
@ -55,11 +55,11 @@ class ClientTest : public ClientBase<HTTP> {
public: public:
ClientTest(const std::string &server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {} ClientTest(const std::string &server_port_path) : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
std::shared_ptr<Connection> create_connection() override { std::shared_ptr<Connection> create_connection() noexcept override {
return nullptr; return nullptr;
} }
void connect(const std::shared_ptr<Session> &) override {} void connect(const std::shared_ptr<Session> &) noexcept override {}
void constructor_parse_test1() { void constructor_parse_test1() {
assert(host == "test.org"); assert(host == "test.org");

View file

@ -9,7 +9,7 @@
#include <unordered_map> #include <unordered_map>
namespace SimpleWeb { namespace SimpleWeb {
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) { inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept {
return str1.size() == str2.size() && return str1.size() == str2.size() &&
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) { std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
return tolower(a) == tolower(b); return tolower(a) == tolower(b);
@ -17,14 +17,14 @@ namespace SimpleWeb {
} }
class CaseInsensitiveEqual { class CaseInsensitiveEqual {
public: public:
bool operator()(const std::string &str1, const std::string &str2) const { bool operator()(const std::string &str1, const std::string &str2) const noexcept {
return case_insensitive_equal(str1, str2); return case_insensitive_equal(str1, str2);
} }
}; };
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226 // Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
class CaseInsensitiveHash { class CaseInsensitiveHash {
public: public:
size_t operator()(const std::string &str) const { size_t operator()(const std::string &str) const noexcept {
size_t h = 0; size_t h = 0;
std::hash<int> hash; std::hash<int> hash;
for(auto c : str) for(auto c : str)
@ -39,7 +39,7 @@ namespace SimpleWeb {
class Percent { class Percent {
public: public:
/// Returns percent-encoded string /// Returns percent-encoded string
static std::string encode(const std::string &value) { static std::string encode(const std::string &value) noexcept {
static auto hex_chars = "0123456789ABCDEF"; static auto hex_chars = "0123456789ABCDEF";
std::string result; std::string result;
@ -58,7 +58,7 @@ namespace SimpleWeb {
} }
/// Returns percent-decoded string /// Returns percent-decoded string
static std::string decode(const std::string &value) { static std::string decode(const std::string &value) noexcept {
std::string result; std::string result;
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
@ -84,7 +84,7 @@ namespace SimpleWeb {
class QueryString { class QueryString {
public: public:
/// Returns query string created from given field names and values /// Returns query string created from given field names and values
static std::string create(const CaseInsensitiveMultimap &fields) { static std::string create(const CaseInsensitiveMultimap &fields) noexcept {
std::string result; std::string result;
bool first = true; bool first = true;
@ -97,7 +97,7 @@ namespace SimpleWeb {
} }
/// Returns query keys with percent-decoded values. /// Returns query keys with percent-decoded values.
static CaseInsensitiveMultimap parse(const std::string &query_string) { static CaseInsensitiveMultimap parse(const std::string &query_string) noexcept {
CaseInsensitiveMultimap result; CaseInsensitiveMultimap result;
if(query_string.empty()) if(query_string.empty())
@ -137,7 +137,7 @@ namespace SimpleWeb {
class RequestMessage { class RequestMessage {
public: public:
/// Parse request line and header fields /// Parse request line and header fields
static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) { static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) noexcept {
header.clear(); header.clear();
std::string line; std::string line;
getline(stream, line); getline(stream, line);
@ -198,7 +198,7 @@ namespace SimpleWeb {
class ResponseMessage { class ResponseMessage {
public: public:
/// Parse status line and header fields /// Parse status line and header fields
static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) { static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) noexcept {
header.clear(); header.clear();
std::string line; std::string line;
getline(stream, line); getline(stream, line);
@ -237,17 +237,17 @@ namespace SimpleWeb {
#ifdef __SSE2__ #ifdef __SSE2__
#include <emmintrin.h> #include <emmintrin.h>
namespace SimpleWeb { namespace SimpleWeb {
inline void spin_loop_pause() { _mm_pause(); } inline void spin_loop_pause() noexcept { _mm_pause(); }
} // namespace SimpleWeb } // namespace SimpleWeb
// TODO: need verification that the following checks are correct: // TODO: need verification that the following checks are correct:
#elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86)) #elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86))
#include <intrin.h> #include <intrin.h>
namespace SimpleWeb { namespace SimpleWeb {
inline void spin_loop_pause() { _mm_pause(); } inline void spin_loop_pause() noexcept { _mm_pause(); }
} // namespace SimpleWeb } // namespace SimpleWeb
#else #else
namespace SimpleWeb { namespace SimpleWeb {
inline void spin_loop_pause() {} inline void spin_loop_pause() noexcept {}
} // namespace SimpleWeb } // namespace SimpleWeb
#endif #endif
@ -261,20 +261,20 @@ namespace SimpleWeb {
class SharedLock { class SharedLock {
friend class ScopeRunner; friend class ScopeRunner;
std::atomic<long> &count; std::atomic<long> &count;
SharedLock(std::atomic<long> &count) : count(count) {} SharedLock(std::atomic<long> &count) noexcept : count(count) {}
SharedLock &operator=(const SharedLock &) = delete; SharedLock &operator=(const SharedLock &) = delete;
SharedLock(const SharedLock &) = delete; SharedLock(const SharedLock &) = delete;
public: public:
~SharedLock() { ~SharedLock() noexcept {
count.fetch_sub(1); count.fetch_sub(1);
} }
}; };
ScopeRunner() : count(0) {} ScopeRunner() noexcept : count(0) {}
/// Returns nullptr if scope should be exited, or a shared lock otherwise /// Returns nullptr if scope should be exited, or a shared lock otherwise
std::unique_ptr<SharedLock> continue_lock() { std::unique_ptr<SharedLock> continue_lock() noexcept {
long expected = count; long expected = count;
while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1)) while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1))
spin_loop_pause(); spin_loop_pause();
@ -286,7 +286,7 @@ namespace SimpleWeb {
} }
//// Blocks until all shared locks are released, then prevents future shared locks //// Blocks until all shared locks are released, then prevents future shared locks
void stop() { void stop() noexcept {
long expected = 0; long expected = 0;
while(!count.compare_exchange_weak(expected, -1)) { while(!count.compare_exchange_weak(expected, -1)) {
if(expected < 0) if(expected < 0)