Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/marian-nmt/Simple-WebSocket-Server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreidheim <eidheim@gmail.com>2017-07-22 14:18:42 +0300
committereidheim <eidheim@gmail.com>2017-07-22 14:18:42 +0300
commit6c4df6ae48b1c73fc9774566655fe7c660831c74 (patch)
tree233458f0093edf16a7cd37468b70f8e44115cd03 /utility.hpp
parent58f8eeb1435ab2b1580d621371518e6f9319a737 (diff)
Updated utility.hpp and added noexcept
Diffstat (limited to 'utility.hpp')
-rw-r--r--utility.hpp170
1 files changed, 54 insertions, 116 deletions
diff --git a/utility.hpp b/utility.hpp
index 70f81db..280ae82 100644
--- a/utility.hpp
+++ b/utility.hpp
@@ -2,13 +2,14 @@
#define SIMPLE_WEB_UTILITY_HPP
#include "status_code.hpp"
+#include <atomic>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
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() &&
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
return tolower(a) == tolower(b);
@@ -16,14 +17,14 @@ namespace SimpleWeb {
}
class CaseInsensitiveEqual {
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);
}
};
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
class CaseInsensitiveHash {
public:
- size_t operator()(const std::string &str) const {
+ size_t operator()(const std::string &str) const noexcept {
size_t h = 0;
std::hash<int> hash;
for(auto c : str)
@@ -38,7 +39,7 @@ namespace SimpleWeb {
class Percent {
public:
/// 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";
std::string result;
@@ -57,7 +58,7 @@ namespace SimpleWeb {
}
/// Returns percent-decoded string
- static std::string decode(const std::string &value) {
+ static std::string decode(const std::string &value) noexcept {
std::string result;
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
@@ -83,7 +84,7 @@ namespace SimpleWeb {
class QueryString {
public:
/// 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;
bool first = true;
@@ -96,7 +97,7 @@ namespace SimpleWeb {
}
/// 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;
if(query_string.empty())
@@ -133,11 +134,10 @@ namespace SimpleWeb {
}
};
-
class RequestMessage {
public:
/// 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();
std::string line;
getline(stream, line);
@@ -198,7 +198,7 @@ namespace SimpleWeb {
class ResponseMessage {
public:
/// 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();
std::string line;
getline(stream, line);
@@ -234,130 +234,68 @@ namespace SimpleWeb {
};
} // namespace SimpleWeb
-#ifdef PTHREAD_RWLOCK_INITIALIZER
+#ifdef __SSE2__
+#include <emmintrin.h>
namespace SimpleWeb {
- /// Read-preferring R/W lock.
- /// Uses pthread_rwlock.
- class SharedMutex {
- pthread_rwlock_t rwlock;
-
- public:
- class SharedLock {
- friend class SharedMutex;
- pthread_rwlock_t &rwlock;
-
- SharedLock(pthread_rwlock_t &rwlock) : rwlock(rwlock) {
- pthread_rwlock_rdlock(&rwlock);
- }
-
- public:
- ~SharedLock() {
- pthread_rwlock_unlock(&rwlock);
- }
- };
-
- class UniqueLock {
- friend class SharedMutex;
- pthread_rwlock_t &rwlock;
-
- UniqueLock(pthread_rwlock_t &rwlock) : rwlock(rwlock) {
- pthread_rwlock_wrlock(&rwlock);
- }
-
- public:
- ~UniqueLock() {
- pthread_rwlock_unlock(&rwlock);
- }
- };
-
- public:
- SharedMutex() {
-
- pthread_rwlock_init(&rwlock, nullptr);
- }
-
- ~SharedMutex() {
- pthread_rwlock_destroy(&rwlock);
- }
-
- std::unique_ptr<SharedLock> shared_lock() {
- return std::unique_ptr<SharedLock>(new SharedLock(rwlock));
- }
-
- std::unique_ptr<UniqueLock> unique_lock() {
- return std::unique_ptr<UniqueLock>(new UniqueLock(rwlock));
- }
- };
+ inline void spin_loop_pause() noexcept { _mm_pause(); }
+} // namespace SimpleWeb
+// TODO: need verification that the following checks are correct:
+#elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86))
+#include <intrin.h>
+namespace SimpleWeb {
+ inline void spin_loop_pause() noexcept { _mm_pause(); }
} // namespace SimpleWeb
#else
-#include <condition_variable>
-#include <mutex>
namespace SimpleWeb {
- /// Read-preferring R/W lock.
- /// Based on https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Using_a_condition_variable_and_a_mutex pseudocode.
- /// TODO: Someone that uses Windows should implement Windows specific R/W locks here.
- class SharedMutex {
- std::mutex m;
- std::condition_variable c;
- int r = 0;
- bool w = false;
+ inline void spin_loop_pause() noexcept {}
+} // namespace SimpleWeb
+#endif
+
+namespace SimpleWeb {
+ /// Makes it possible to for instance cancel Asio handlers without stopping asio::io_service
+ class ScopeRunner {
+ /// Scope count that is set to -1 if scopes are to be canceled
+ std::atomic<long> count;
public:
class SharedLock {
- friend class SharedMutex;
- std::condition_variable &c;
- int &r;
- std::unique_lock<std::mutex> lock;
-
- SharedLock(std::mutex &m, std::condition_variable &c, int &r, bool &w) : c(c), r(r), lock(m) {
- while(w)
- c.wait(lock);
- ++r;
- lock.unlock();
- }
+ friend class ScopeRunner;
+ std::atomic<long> &count;
+ SharedLock(std::atomic<long> &count) noexcept : count(count) {}
+ SharedLock &operator=(const SharedLock &) = delete;
+ SharedLock(const SharedLock &) = delete;
public:
- ~SharedLock() {
- lock.lock();
- --r;
- if(r == 0)
- c.notify_all();
- lock.unlock();
+ ~SharedLock() noexcept {
+ count.fetch_sub(1);
}
};
- class UniqueLock {
- friend class SharedMutex;
- std::condition_variable &c;
- bool &w;
- std::unique_lock<std::mutex> lock;
-
- UniqueLock(std::mutex &m, std::condition_variable &c, int &r, bool &w) : c(c), w(w), lock(m) {
- while(w || r > 0)
- c.wait(lock);
- w = true;
- lock.unlock();
- }
+ ScopeRunner() noexcept : count(0) {}
- public:
- ~UniqueLock() {
- lock.lock();
- w = false;
- c.notify_all();
- lock.unlock();
- }
- };
+ /// Returns nullptr if scope should be exited, or a shared lock otherwise
+ std::unique_ptr<SharedLock> continue_lock() noexcept {
+ long expected = count;
+ while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1))
+ spin_loop_pause();
- public:
- std::unique_ptr<SharedLock> shared_lock() {
- return std::unique_ptr<SharedLock>(new SharedLock(m, c, r, w));
+ if(expected < 0)
+ return nullptr;
+ else
+ return std::unique_ptr<SharedLock>(new SharedLock(count));
}
- std::unique_ptr<UniqueLock> unique_lock() {
- return std::unique_ptr<UniqueLock>(new UniqueLock(m, c, r, w));
+ //// Blocks until all shared locks are released, then prevents future shared locks
+ void stop() noexcept {
+ long expected = 0;
+ while(!count.compare_exchange_weak(expected, -1)) {
+ if(expected < 0)
+ return;
+ expected = 0;
+ spin_loop_pause();
+ }
}
};
} // namespace SimpleWeb
-#endif
#endif // SIMPLE_WEB_UTILITY_HPP