diff options
author | eidheim <eidheim@gmail.com> | 2017-07-22 14:18:42 +0300 |
---|---|---|
committer | eidheim <eidheim@gmail.com> | 2017-07-22 14:18:42 +0300 |
commit | 6c4df6ae48b1c73fc9774566655fe7c660831c74 (patch) | |
tree | 233458f0093edf16a7cd37468b70f8e44115cd03 /utility.hpp | |
parent | 58f8eeb1435ab2b1580d621371518e6f9319a737 (diff) |
Updated utility.hpp and added noexcept
Diffstat (limited to 'utility.hpp')
-rw-r--r-- | utility.hpp | 170 |
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 |