diff --git a/Builds/VisualStudio2013/beast.vcxproj b/Builds/VisualStudio2013/beast.vcxproj index 6bceab509..6e32692d5 100644 --- a/Builds/VisualStudio2013/beast.vcxproj +++ b/Builds/VisualStudio2013/beast.vcxproj @@ -21,6 +21,7 @@ + @@ -86,8 +87,10 @@ + + @@ -133,6 +136,7 @@ + @@ -152,7 +156,6 @@ - @@ -185,14 +188,12 @@ - - @@ -214,7 +215,6 @@ - @@ -333,7 +333,6 @@ - @@ -362,10 +361,7 @@ - - - @@ -433,6 +429,30 @@ true true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + @@ -1115,12 +1135,6 @@ true true - - true - true - true - true - true true @@ -1163,12 +1177,6 @@ true true - - true - true - true - true - true true @@ -1277,12 +1285,6 @@ true true - - true - true - true - true - true true diff --git a/Builds/VisualStudio2013/beast.vcxproj.filters b/Builds/VisualStudio2013/beast.vcxproj.filters index 09b0c43b5..dab2e43ca 100644 --- a/Builds/VisualStudio2013/beast.vcxproj.filters +++ b/Builds/VisualStudio2013/beast.vcxproj.filters @@ -76,6 +76,9 @@ scripts + + beast\asio + @@ -309,6 +312,9 @@ {1271ee71-5754-46ef-845b-84e53eed11c0} + + {f2594738-6447-447b-8f51-2d42fbe8a6ee} + @@ -419,9 +425,6 @@ beast_core\network - - beast_core\network - beast_core\network @@ -482,18 +485,9 @@ beast_core\threads - - beast_core\threads - beast_core\threads - - beast_core\threads - - - beast_core\threads - beast_core\time @@ -956,9 +950,6 @@ beast - - beast - beast\utility @@ -1014,9 +1005,6 @@ beast\net - - beast\net - beast_asio\http @@ -1032,9 +1020,6 @@ beast - - beast\threads - beast\threads @@ -1149,9 +1134,6 @@ beast\insight - - beast - beast\threads @@ -1323,6 +1305,15 @@ beast\http\impl + + beast\container + + + beast\asio + + + beast\asio + @@ -1406,9 +1397,6 @@ beast_core\native - - beast_core\native - beast_core\native @@ -1427,9 +1415,6 @@ beast_core\network - - beast_core\network - beast_core\network @@ -1475,9 +1460,6 @@ beast_core\threads - - beast_core\threads - beast_core\time @@ -1910,6 +1892,18 @@ beast\asio + + beast\asio\tests + + + beast\asio\tests + + + beast\asio\tests + + + beast\asio\tests + diff --git a/TODO.txt b/TODO.txt index 32bdb06ae..169787991 100644 --- a/TODO.txt +++ b/TODO.txt @@ -58,8 +58,6 @@ BEAST TODO - Rename SharedData to SharedState or something? -- Figure out what to do with ReadWriteLock, and NamedPipe which uses it? - - Put BEAST_PUBLIC_FUNCTION in front of all loose functions - restructure the repo sources to look like this: diff --git a/beast/Net.h b/beast/Net.h index cd03ad112..6c4862d88 100644 --- a/beast/Net.h +++ b/beast/Net.h @@ -20,7 +20,6 @@ #ifndef BEAST_NET_H_INCLUDED #define BEAST_NET_H_INCLUDED -#include "net/BufferType.h" #include "net/DynamicBuffer.h" #include "net/IPEndpoint.h" diff --git a/beast/SafeBool.h b/beast/SafeBool.h deleted file mode 100644 index fbae19592..000000000 --- a/beast/SafeBool.h +++ /dev/null @@ -1,95 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_SAFEBOOL_H_INCLUDED -#define BEAST_SAFEBOOL_H_INCLUDED - -namespace beast { - -namespace detail { - -class SafeBoolBase -{ -private: - void disallowed () const { } - -public: - void allowed () const { } - -protected: - typedef void (SafeBoolBase::*boolean_t) () const; - - SafeBoolBase () { } - SafeBoolBase (SafeBoolBase const&) { } - SafeBoolBase& operator= (SafeBoolBase const&) - { - return *this; - } - ~SafeBoolBase () { } -}; - -} - -/** Safe evaluation of class as `bool`. - - This allows a class to be safely evaluated as a bool without the usual - harmful side effects of the straightforward operator conversion approach. - To use it, derive your class from SafeBool and implement `asBoolean()` as: - - @code - - bool asBoolean () const; - - @endcode - - Ideas from http://www.artima.com/cppsource/safebool.html - - @class SafeBool -*/ -template -class SafeBool : public detail::SafeBoolBase -{ -public: - operator detail::SafeBoolBase::boolean_t () const - { - return (static_cast (this))->asBoolean () - ? &SafeBoolBase::allowed : 0; - } - -protected: - ~SafeBool () { } -}; - -template -void operator== (SafeBool const& lhs, SafeBool const& rhs) -{ - lhs.disallowed (); -} - -template -void operator!= (SafeBool const& lhs, SafeBool const& rhs) -{ - lhs.disallowed (); -} - -} - -#endif - - diff --git a/beast/Threads.h b/beast/Threads.h index bd7a9c814..756376a2f 100644 --- a/beast/Threads.h +++ b/beast/Threads.h @@ -20,7 +20,6 @@ #ifndef BEAST_THREADS_H_INCLUDED #define BEAST_THREADS_H_INCLUDED -#include "threads/LockGuard.h" #include "threads/UnlockGuard.h" #include "threads/TryLockGuard.h" #include "threads/SharedLockGuard.h" diff --git a/beast/asio/Asio.cpp b/beast/asio/Asio.cpp index aada5e4b3..d578299ff 100644 --- a/beast/asio/Asio.cpp +++ b/beast/asio/Asio.cpp @@ -23,6 +23,7 @@ #include "tests/wrap_handler_tests.cpp" #include "tests/bind_handler_tests.cpp" +#include "tests/enable_wait_for_async.test.cpp" #include "tests/shared_handler_tests.cpp" #include "abstract_socket.cpp" // TEMPORARY! diff --git a/beast/asio/README.md b/beast/asio/README.md new file mode 100644 index 000000000..5344652e2 --- /dev/null +++ b/beast/asio/README.md @@ -0,0 +1,14 @@ +# beast::asio + +Wrappers and utilities to make working with boost::asio easier. + +## Rules for asynchronous objects + +If an object calls asynchronous initiating functions it must either: + + 1. Manage its lifetime by being reference counted + + or + + 2. Wait for all pending completion handlers to be called before + allowing itself to be destroyed. diff --git a/beast/asio/buffer_sequence.h b/beast/asio/buffer_sequence.h index b392e1ed5..3efec2230 100644 --- a/beast/asio/buffer_sequence.h +++ b/beast/asio/buffer_sequence.h @@ -99,6 +99,21 @@ public: { return m_buffers.end (); } + +#if 0 + template + void + assign (ConstBufferSequence const& buffers) + { + auto const n (std::distance ( + std::begin (buffers), std::end (buffers))); + + for (int i = 0, auto iter (std::begin (buffers)); + iter != std::end (buffers); ++iter, ++i) + m_buffers[i] = Buffer (boost::asio::buffer_cast ( + *iter), boost::asio::buffer_size (*iter)); + } +#endif }; typedef buffer_sequence const_buffers; diff --git a/beast/asio/enable_wait_for_async.h b/beast/asio/enable_wait_for_async.h new file mode 100644 index 000000000..f6b877a80 --- /dev/null +++ b/beast/asio/enable_wait_for_async.h @@ -0,0 +1,265 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_ASIO_ENABLE_WAIT_FOR_ASYNC_H_INCLUDED +#define BEAST_ASIO_ENABLE_WAIT_FOR_ASYNC_H_INCLUDED + +#include "wrap_handler.h" + +#include "../mpl/IsCallPossible.h" + +#include +#include +#include + +#include +#include +#include +#include "../cxx14/type_traits.h" // + +namespace beast { +namespace asio { + +namespace detail { + +template +class ref_counted_wrapped_handler +{ +private: + static_assert (std::is_same , Owner>::value, + "Owner cannot be a const or reference type"); + + Handler m_handler; + std::reference_wrapper m_owner; + bool m_continuation; + +public: + ref_counted_wrapped_handler (Owner& owner, + Handler&& handler, bool continuation) + : m_handler (std::move (handler)) + , m_owner (owner) + , m_continuation (continuation ? true : + boost_asio_handler_cont_helpers::is_continuation (m_handler)) + { + m_owner.get().increment(); + } + + ref_counted_wrapped_handler (Owner& owner, + Handler const& handler, bool continuation) + : m_handler (handler) + , m_owner (owner) + , m_continuation (continuation ? true : + boost_asio_handler_cont_helpers::is_continuation (m_handler)) + { + m_owner.get().increment(); + } + + ~ref_counted_wrapped_handler () + { + m_owner.get().decrement(); + } + + ref_counted_wrapped_handler (ref_counted_wrapped_handler const& other) + : m_handler (other.m_handler) + , m_owner (other.m_owner) + , m_continuation (other.m_continuation) + { + m_owner.get().increment(); + } + + ref_counted_wrapped_handler (ref_counted_wrapped_handler&& other) + : m_handler (std::move (other.m_handler)) + , m_owner (other.m_owner) + , m_continuation (other.m_continuation) + { + m_owner.get().increment(); + } + + ref_counted_wrapped_handler& operator= ( + ref_counted_wrapped_handler const&) = delete; + + template + void + operator() (Args&&... args) + { + m_handler (std::forward (args)...); + } + + template + void + operator() (Args&&... args) const + { + m_handler (std::forward (args)...); + } + + template + friend + void + asio_handler_invoke (Function& f, + ref_counted_wrapped_handler* h) + { + boost_asio_handler_invoke_helpers:: + invoke (f, h->m_handler); + } + + template + friend + void + asio_handler_invoke (Function const& f, + ref_counted_wrapped_handler* h) + { + boost_asio_handler_invoke_helpers:: + invoke (f, h->m_handler); + } + + friend + void* + asio_handler_allocate (std::size_t size, + ref_counted_wrapped_handler* h) + { + return boost_asio_handler_alloc_helpers:: + allocate (size, h->m_handler); + } + + friend + void + asio_handler_deallocate (void* p, std::size_t size, + ref_counted_wrapped_handler* h) + { + boost_asio_handler_alloc_helpers:: + deallocate (p, size, h->m_handler); + } + + friend + bool + asio_handler_is_continuation (ref_counted_wrapped_handler* h) + { + return h->m_continuation; + } +}; + +} + +//------------------------------------------------------------------------------ + +/** Facilitates blocking until no completion handlers are remaining. + If Derived has this member function: + + @code + void on_wait_for_async (void) + @endcode + + Then it will be called every time the number of pending completion + handlers transitions to zero from a non-zero value. The call is made + while holding the internal mutex. +*/ +template +class enable_wait_for_async +{ +private: + BEAST_DEFINE_IS_CALL_POSSIBLE( + has_on_wait_for_async,on_wait_for_async); + + void increment() + { + std::lock_guard lock (m_mutex); + ++m_count; + } + + void notify (std::true_type) + { + static_cast (this)->on_wait_for_async(); + } + + void notify (std::false_type) + { + } + + void decrement() + { + std::lock_guard lock (m_mutex); + --m_count; + if (m_count == 0) + { + m_cond.notify_all(); + notify (std::integral_constant ::value>()); + } + } + + template + friend class detail::ref_counted_wrapped_handler; + + std::mutex m_mutex; + std::condition_variable m_cond; + std::size_t m_count; + +public: + /** Blocks if there are any pending completion handlers. */ + void + wait_for_async() + { + std::unique_lock lock (m_mutex); + while (m_count != 0) + m_cond.wait (lock); + } + +protected: + enable_wait_for_async() + : m_count (0) + { + } + + ~enable_wait_for_async() + { + assert (m_count == 0); + } + + /** Wraps the specified handler so it can be counted. */ + /** @{ */ + template + detail::ref_counted_wrapped_handler < + enable_wait_for_async, + std::remove_reference_t + > + wrap_with_counter (Handler&& handler, bool continuation = false) + { + return detail::ref_counted_wrapped_handler > (*this, + std::forward (handler), continuation); + } + + template + detail::ref_counted_wrapped_handler < + enable_wait_for_async, + std::remove_reference_t + > + wrap_with_counter (continuation_t, Handler&& handler) + { + return detail::ref_counted_wrapped_handler > (*this, + std::forward (handler), true); + } + /** @} */ +}; + +} +} + +#endif diff --git a/beast/asio/memory_buffer.h b/beast/asio/memory_buffer.h new file mode 100644 index 000000000..e77d1d420 --- /dev/null +++ b/beast/asio/memory_buffer.h @@ -0,0 +1,423 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_ASIO_MEMORY_BUFFER_H_INCLUDED +#define BEAST_ASIO_MEMORY_BUFFER_H_INCLUDED + +#include "../utility/empty_base_optimization.h" + +#include + +#include +#include + +namespace beast { +namespace asio { + +template < + class T, + class Alloc = std::allocator +> +class memory_buffer + : private empty_base_optimization +{ +private: + static_assert (std::is_trivially_constructible ::value, + "T must be trivially constructible"); + + typedef empty_base_optimization Base; + + using AllocTraits = std::allocator_traits ; + + T* m_base; + std::size_t m_size; + +public: + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T& reference; + typedef T const& const_reference; + typedef T* pointer; + typedef T const* const_pointer; + typedef Alloc allocator_type; + typedef T* iterator; + typedef T const* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + memory_buffer () + : m_base (nullptr) + , m_size (0) + { + } + + memory_buffer (memory_buffer&& other) + : Base (std::move (other)) + , m_base (other.m_base) + , m_size (other.m_size) + { + other.m_base = nullptr; + other.m_size = 0; + } + + explicit memory_buffer (size_type n) + : m_base (AllocTraits::allocate (Base::member(), n)) + , m_size (n) + { + } + + explicit memory_buffer (Alloc const& alloc) + : Base (alloc) + , m_base (nullptr) + , m_size (0) + { + } + + memory_buffer (size_type n, Alloc const& alloc) + : Base (alloc) + , m_base (AllocTraits::allocate (Base::member(), n)) + , m_size (n) + { + } + + ~memory_buffer() + { + if (m_base != nullptr) + AllocTraits::deallocate (Base::member(), m_base, m_size); + } + + memory_buffer& operator= (memory_buffer const&) = delete; + + allocator_type + get_allocator() const + { + return Base::member; + } + + // + // asio support + // + + boost::asio::mutable_buffer + buffer() + { + return boost::asio::mutable_buffer ( + data(), bytes()); + } + + boost::asio::const_buffer + buffer() const + { + return boost::asio::const_buffer ( + data(), bytes()); + } + + boost::asio::mutable_buffers_1 + buffers() + { + return boost::asio::mutable_buffers_1 ( + data(), bytes()); + } + + boost::asio::const_buffers_1 + buffers() const + { + return boost::asio::const_buffers_1 ( + data(), bytes()); + } + + operator boost::asio::mutable_buffer() + { + return buffer(); + } + + operator boost::asio::const_buffer() const + { + return buffer(); + } + + operator boost::asio::mutable_buffers_1() + { + return buffers(); + } + + operator boost::asio::const_buffers_1() const + { + return buffers(); + } + + // + // Element access + // + + reference + at (size_type pos) + { + if (! (pos < size())) + throw std::out_of_range ("bad array index"); + return m_base [pos]; + } + + const_reference + at (size_type pos) const + { + if (! (pos < size())) + throw std::out_of_range ("bad array index"); + return m_base [pos]; + } + + reference + operator[] (size_type pos) noexcept + { + return m_base [pos]; + } + + const_reference + operator[] (size_type pos) const noexcept + { + return m_base [pos]; + } + + reference + back() noexcept + { + return m_base [m_size - 1]; + } + + const_reference + back() const noexcept + { + return m_base [m_size - 1]; + } + + reference + front() noexcept + { + return *m_base; + } + + const_reference + front() const noexcept + { + return *m_base; + } + + pointer + data() noexcept + { + return m_base; + } + + const_pointer + data() const noexcept + { + return m_base; + } + + // + // Iterators + // + + iterator + begin() noexcept + { + return m_base; + } + + const_iterator + begin() const noexcept + { + return m_base; + } + + const_iterator + cbegin() const noexcept + { + return m_base; + } + + iterator + end() noexcept + { + return m_base + m_size; + } + + const_iterator + end() const noexcept + { + return m_base + m_size; + } + + const_iterator + cend() const noexcept + { + return m_base + m_size; + } + + reverse_iterator + rbegin() noexcept + { + return reverse_iterator (end()); + } + + const_reverse_iterator + rbegin() const noexcept + { + return const_reverse_iterator (cend()); + } + + const_reverse_iterator + crbegin() const noexcept + { + return const_reverse_iterator (cend()); + } + + reverse_iterator + rend() noexcept + { + return reverse_iterator (begin()); + } + + const_reverse_iterator + rend() const noexcept + { + return const_reverse_iterator (cbegin()); + } + + const_reverse_iterator + crend() const noexcept + { + return const_reverse_iterator (cbegin()); + } + + // + // Capacity + // + + bool + empty() const noexcept + { + return m_size == 0; + } + + size_type + size() const noexcept + { + return m_size; + } + + size_type + max_size() const noexcept + { + return size(); + } + + size_type + capacity() const noexcept + { + return size(); + } + + size_type bytes() const + { + return m_size * sizeof(T); + } + + // + // Modifiers + // + + template + friend + void + swap (memory_buffer & lhs, + memory_buffer & rhs) noexcept; +}; + +//------------------------------------------------------------------------------ + +template +void +swap (memory_buffer & lhs, + memory_buffer & rhs) noexcept +{ + std::swap (lhs.m_base, rhs.m_base); + std::swap (lhs.m_size, rhs.m_size); +} + +template +inline +bool +operator== (memory_buffer const& lhs, + memory_buffer const& rhs) +{ + return std::equal (lhs.cbegin(), lhs.cend(), + rhs.cbegin(), rhs.cend()); +} + +template +inline +bool +operator!= (memory_buffer const& lhs, + memory_buffer const& rhs) +{ + return ! (lhs == rhs); +} + +template +inline +bool +operator< (memory_buffer const& lhs, + memory_buffer const& rhs) +{ + return std::lexicographical_compare ( + lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); +} + +template +inline +bool +operator>= (memory_buffer const& lhs, + memory_buffer const& rhs) +{ + return ! (lhs < rhs); +} + +template +inline +bool +operator> (memory_buffer const& lhs, + memory_buffer const& rhs) +{ + return rhs < lhs; +} + +template +inline +bool +operator<= (memory_buffer const& lhs, + memory_buffer const& rhs) +{ + return ! (rhs < lhs); +} + +} +} + +#endif diff --git a/beast/asio/shared_handler.h b/beast/asio/shared_handler.h index 21a9c4aaf..78e56d19c 100644 --- a/beast/asio/shared_handler.h +++ b/beast/asio/shared_handler.h @@ -20,6 +20,8 @@ #ifndef BEAST_ASIO_SHARED_HANDLER_H_INCLUDED #define BEAST_ASIO_SHARED_HANDLER_H_INCLUDED +#include "../Config.h" + #include "../mpl/IsCallPossible.h" #include @@ -260,9 +262,7 @@ public: //------------------------------------------------------------------------------ /** Handler shared reference that provides io_service execution guarantees. */ -template < - class Signature -> +template class shared_handler { private: @@ -318,6 +318,7 @@ public: operator= (std::nullptr_t) { m_ptr = nullptr; + return *this; } shared_handler& @@ -327,15 +328,17 @@ public: return *this; } - bool - empty() const + shared_handler& + operator= (shared_handler&& rhs) { - return ! m_ptr.operator bool(); + m_ptr = std::move (rhs.m_ptr); + return *this; } - operator bool() const + explicit + operator bool() const noexcept { - return !empty(); + return m_ptr.operator bool(); } void diff --git a/beast/asio/socket_wrapper.h b/beast/asio/socket_wrapper.h index 9182943c5..136ad0898 100644 --- a/beast/asio/socket_wrapper.h +++ b/beast/asio/socket_wrapper.h @@ -225,14 +225,9 @@ private: boost::asio::io_service& get_io_service () override { -#if 0 - // Apparently has_get_io_service always results in false return get_io_service ( Enabled > ()); -#else - return get_io_service (std::true_type ()); -#endif } boost::asio::io_service& get_io_service ( diff --git a/beast/asio/tests/enable_wait_for_async.test.cpp b/beast/asio/tests/enable_wait_for_async.test.cpp new file mode 100644 index 000000000..1822e446d --- /dev/null +++ b/beast/asio/tests/enable_wait_for_async.test.cpp @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "../../../modules/beast_core/beast_core.h" // for UnitTest + +#include "../bind_handler.h" +#include "../enable_wait_for_async.h" + +#include + +namespace beast { + +class enable_wait_for_async_Tests : public UnitTest +{ +public: + typedef boost::system::error_code error_code; + + void test() + { + struct handler + { + void operator()(error_code) + { + } + }; + + struct owner : asio::enable_wait_for_async + { + bool notified; + + owner() + : notified (false) + { + } + + void operator()() + { + { + boost::asio::io_service ios; + ios.post (asio::bind_handler (handler(), + error_code())); + ios.run(); + ios.reset(); + wait_for_async(); + } + + { + boost::asio::io_service ios; + ios.post (wrap_with_counter (asio::bind_handler ( + handler(), error_code()))); + ios.run(); + wait_for_async(); + } + + { + boost::asio::io_service ios; + handler h; + ios.post (wrap_with_counter (std::bind ( + &handler::operator(), &h, + error_code()))); + ios.run(); + wait_for_async(); + } + } + + void on_wait_for_async() + { + notified = true; + } + }; + + beginTestCase ("wait_for_async"); + owner o; + o(); + expect (o.notified); + } + + void runTest() + { + test(); + } + + enable_wait_for_async_Tests() : UnitTest ("enable_wait_for_async", "beast") + { + } +}; + +static enable_wait_for_async_Tests enable_wait_for_async_tests; + +} diff --git a/beast/cyclic_iterator.h b/beast/container/cyclic_iterator.h similarity index 100% rename from beast/cyclic_iterator.h rename to beast/container/cyclic_iterator.h diff --git a/beast/crypto/UnsignedInteger.h b/beast/crypto/UnsignedInteger.h index 09a87c74f..b276e1286 100644 --- a/beast/crypto/UnsignedInteger.h +++ b/beast/crypto/UnsignedInteger.h @@ -20,7 +20,6 @@ #ifndef BEAST_CRYPTO_UNSIGNEDINTEGER_H_INCLUDED #define BEAST_CRYPTO_UNSIGNEDINTEGER_H_INCLUDED -#include "../SafeBool.h" #include "UnsignedIntegerCalc.h" #include "MurmurHash.h" @@ -38,7 +37,7 @@ namespace beast { may not be aligned. */ template -class UnsignedInteger : public SafeBool > +class UnsignedInteger { public: /** Constant for determining the number of bytes. */ @@ -201,9 +200,9 @@ public: /** Support conversion to `bool`. @return `true` if any bit is non-zero. - @see SafeBool */ - bool asBoolean () const + explicit + operator bool() const { return isNotZero (); } diff --git a/beast/crypto/UnsignedIntegerCalc.h b/beast/crypto/UnsignedIntegerCalc.h index fffadfab7..ef1d48120 100644 --- a/beast/crypto/UnsignedIntegerCalc.h +++ b/beast/crypto/UnsignedIntegerCalc.h @@ -60,7 +60,7 @@ struct DoubleWidthUInt which return results by value cannot be included in the interface. */ template -class UnsignedIntegerCalc : public SafeBool > +class UnsignedIntegerCalc { public: typedef typename detail::DoubleWidthUInt ::type UIntBig; @@ -182,7 +182,8 @@ public: } /** Safe conversion to `bool`, `true` means a non-zero value. */ - bool asBoolean () const + explicit + operator bool() const { return isNotZero (); } diff --git a/beast/mpl/IsCallPossible.h b/beast/mpl/IsCallPossible.h index bc85184ae..ae40180fc 100644 --- a/beast/mpl/IsCallPossible.h +++ b/beast/mpl/IsCallPossible.h @@ -20,6 +20,8 @@ #ifndef BEAST_MPL_ISCALLPOSSIBLE_H_INCLUDED #define BEAST_MPL_ISCALLPOSSIBLE_H_INCLUDED +#include "../cxx14/type_traits.h" // + namespace beast { namespace mpl { @@ -160,10 +162,11 @@ struct trait_name##_detail BEAST_DEFINE_HAS_MEMBER_FUNCTION(has_member, member_function_name); \ }; \ \ -template \ +template \ struct trait_name \ { \ - private: \ +private: \ + typedef std::remove_reference_t
T; \ class yes {}; \ class no { yes m[2]; }; \ struct derived : public T \ @@ -197,6 +200,18 @@ struct trait_name static const bool value = false; \ }; \ \ + template \ + struct impl \ + { \ + static typename beast::mpl::is_call_possible_detail::add_reference::type test_me; \ + \ + static const bool value = \ + sizeof( \ + return_value_check::deduce( \ + (test_me.member_function_name(), beast::mpl::is_call_possible_detail::void_exp_result())) \ + ) == sizeof(yes); \ + }; \ + \ template \ struct impl \ { \ diff --git a/beast/net/BufferType.h b/beast/net/BufferType.h deleted file mode 100644 index ae5c24004..000000000 --- a/beast/net/BufferType.h +++ /dev/null @@ -1,106 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_NET_BASICS_BUFFERTYPE_H_INCLUDED -#define BEAST_NET_BASICS_BUFFERTYPE_H_INCLUDED - -#include - -namespace beast { - -/** General linear memory buffer. - This wraps the underlying buffer type and provides additional methods - to create a uniform interface. Specializations allow asio-compatible - buffers without having to include boost/asio.h. -*/ -/** @{ */ -template -class BufferType -{ -private: - typedef typename std::conditional ::type pointer_type; - - typedef typename std::conditional ::type byte_type; - -public: - typedef std::size_t size_type; - - BufferType () - : m_data (nullptr) - , m_size (0) - { - } - - template - BufferType (BufferType const& other) - : m_data (other.template cast ()) - , m_size (other.size ()) - { - } - - BufferType (pointer_type data, std::size_t size) noexcept - : m_data (data) - , m_size (size) - { - } - - BufferType& operator= (BufferType const& other) noexcept - { - m_data = other.cast (); - m_size = other.size (); - return *this; - } - - template - BufferType& operator= ( - BufferType const& other) noexcept - { - m_data = other.template cast (); - m_size = other.size (); - return *this; - } - - template - T cast () const noexcept - { - return static_cast (m_data); - } - - size_type size () const - { - return m_size; - } - - BufferType operator+ (size_type n) const noexcept - { - return BufferType (cast (), - size () - std::min (size(), n)); - } - -private: - pointer_type m_data; - std::size_t m_size; -}; -/** @} */ - -} - -#endif diff --git a/beast/net/IPAddress.h b/beast/net/IPAddress.h index 0211677af..65e8c32b5 100644 --- a/beast/net/IPAddress.h +++ b/beast/net/IPAddress.h @@ -40,61 +40,159 @@ class Address { public: /** Create an unspecified IPv4 address. */ - Address (); + Address () + : m_type (ipv4) + { + } /** Create an IPv4 address. */ - Address (AddressV4 const& addr); + Address (AddressV4 const& addr) + : m_type (ipv4) + , m_v4 (addr) + { + } /** Create an IPv6 address. */ - Address (AddressV6 const& addr); + Address (AddressV6 const& addr) + : m_type (ipv6) + , m_v6 (addr) + { + } /** Assign a copy from another address in any format. */ /** @{ */ - Address& operator= (AddressV4 const& addr); - Address& operator= (AddressV6 const& addr); + Address& + operator= (AddressV4 const& addr) + { + m_type = ipv4; + m_v6 = AddressV6(); + m_v4 = addr; + return *this; + } + + Address& + operator= (AddressV6 const& addr) + { + m_type = ipv6; + m_v4 = AddressV4(); + m_v6 = addr; + return *this; + } /** @} */ /** Create an Address from a string. @return A pair with the address, and bool set to `true` on success. */ - static std::pair from_string (std::string const& s); + static + std::pair + from_string (std::string const& s); /** Returns a string representing the address. */ - std::string to_string () const; + std::string + to_string () const + { + return (is_v4 ()) + ? IP::to_string (to_v4()) + : IP::to_string (to_v6()); + } /** Returns `true` if this address represents an IPv4 address. */ - bool is_v4 () const - { return m_type == ipv4; } + bool + is_v4 () const + { + return m_type == ipv4; + } /** Returns `true` if this address represents an IPv6 address. */ - bool is_v6 () const - { return m_type == ipv6; } + bool + is_v6() const + { + return m_type == ipv6; + } /** Returns the IPv4 address. Precondition: - is_v4() returns true + is_v4() == `true` */ - AddressV4 const& to_v4 () const; + AddressV4 const& + to_v4 () const + { + if (m_type != ipv4) + throw std::bad_cast(); + return m_v4; + } + /** Returns the IPv6 address. Precondition: - is_v6() returns true + is_v6() == `true` */ - AddressV6 const& to_v6 () const; + AddressV6 const& + to_v6 () const + { + if (m_type != ipv6) + throw std::bad_cast(); + return m_v6; + } /** Arithmetic comparison. */ /** @{ */ - friend bool operator== (Address const& lhs, Address const& rhs); - friend bool operator< (Address const& lhs, Address const& rhs); + friend + bool + operator== (Address const& lhs, Address const& rhs) + { + if (lhs.is_v4 ()) + { + if (rhs.is_v4 ()) + return lhs.to_v4() == rhs.to_v4(); + } + else + { + if (rhs.is_v6 ()) + return lhs.to_v6() == rhs.to_v6(); + } - friend bool operator!= (Address const& lhs, Address const& rhs) - { return ! (lhs == rhs); } - friend bool operator> (Address const& lhs, Address const& rhs) - { return rhs < lhs; } - friend bool operator<= (Address const& lhs, Address const& rhs) - { return ! (lhs > rhs); } - friend bool operator>= (Address const& lhs, Address const& rhs) - { return ! (rhs > lhs); } + return false; + } + + friend + bool + operator< (Address const& lhs, Address const& rhs) + { + if (lhs.m_type < rhs.m_type) + return true; + if (lhs.is_v4 ()) + return lhs.to_v4() < rhs.to_v4(); + return lhs.to_v6() < rhs.to_v6(); + } + + friend + bool + operator!= (Address const& lhs, Address const& rhs) + { + return ! (lhs == rhs); + } + + friend + bool + operator> (Address const& lhs, Address const& rhs) + { + return rhs < lhs; + } + + friend + bool + operator<= (Address const& lhs, Address const& rhs) + { + return ! (lhs > rhs); + } + + friend + bool + operator>= (Address const& lhs, Address const& rhs) + { + return ! (rhs > lhs); + } /** @} */ private: @@ -114,36 +212,104 @@ private: // Properties /** Returns `true` if this is a loopback address. */ -bool is_loopback (Address const& addr); +inline +bool +is_loopback (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_loopback (addr.to_v4 ()) + : is_loopback (addr.to_v6 ()); +} /** Returns `true` if the address is unspecified. */ -bool is_unspecified (Address const& addr); +inline +bool +is_unspecified (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_unspecified (addr.to_v4 ()) + : is_unspecified (addr.to_v6 ()); +} /** Returns `true` if the address is a multicast address. */ -bool is_multicast (Address const& addr); +inline +bool +is_multicast (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_multicast (addr.to_v4 ()) + : is_multicast (addr.to_v6 ()); +} /** Returns `true` if the address is a private unroutable address. */ -bool is_private (Address const& addr); +inline +bool +is_private (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_private (addr.to_v4 ()) + : is_private (addr.to_v6 ()); +} /** Returns `true` if the address is a public routable address. */ -bool is_public (Address const& addr); +inline +bool +is_public (Address const& addr) +{ + return (addr.is_v4 ()) + ? is_public (addr.to_v4 ()) + : is_public (addr.to_v6 ()); +} //------------------------------------------------------------------------------ /** boost::hash support. */ -std::size_t hash_value (Address const& addr); +inline +std::size_t +hash_value (Address const& addr) +{ + return (addr.is_v4 ()) + ? hash_value (addr.to_v4()) + : hash_value (addr.to_v6()); +} /** Returns the address represented as a string. */ inline std::string to_string (Address const& addr) - { return addr.to_string (); } +{ + return addr.to_string (); +} /** Output stream conversion. */ template -OutputStream& operator<< (OutputStream& os, Address const& addr) - { return os << to_string (addr); } +OutputStream& +operator<< (OutputStream& os, Address const& addr) +{ + return os << to_string (addr); +} /** Input stream conversion. */ -std::istream& operator>> (std::istream& is, Address& addr); +inline +std::istream& +operator>> (std::istream& is, Address& addr) +{ + // VFALCO TODO Support ipv6! + AddressV4 addrv4; + is >> addrv4; + addr = Address (addrv4); + return is; +} + +inline +std::pair +Address::from_string (std::string const& s) +{ + std::stringstream is (s); + Address addr; + is >> addr; + if (! is.fail() && is.rdbuf()->in_avail() == 0) + return std::make_pair (addr, true); + return std::make_pair (Address (), false); +} } } @@ -154,8 +320,11 @@ namespace std { template <> struct hash { - std::size_t operator() (beast::IP::Address const& addr) const - { return hash_value (addr); } + std::size_t + operator() (beast::IP::Address const& addr) const + { + return hash_value (addr); + } }; } diff --git a/beast/net/impl/IPAddress.cpp b/beast/net/impl/IPAddress.cpp index e01e74c8b..f1edc2a8b 100644 --- a/beast/net/impl/IPAddress.cpp +++ b/beast/net/impl/IPAddress.cpp @@ -25,150 +25,6 @@ namespace beast { namespace IP { -Address::Address () - : m_type (ipv4) -{ -} - -Address::Address (AddressV4 const& addr) - : m_type (ipv4) - , m_v4 (addr) -{ -} - -Address::Address (AddressV6 const& addr) - : m_type (ipv6) - , m_v6 (addr) -{ -} - -Address& Address::operator= (AddressV4 const& addr) -{ - m_type = ipv4; - m_v6 = AddressV6(); - m_v4 = addr; - return *this; -} - -Address& Address::operator= (AddressV6 const& addr) -{ - m_type = ipv6; - m_v4 = AddressV4(); - m_v6 = addr; - return *this; -} - -std::pair Address::from_string (std::string const& s) -{ - std::stringstream is (s); - Address addr; - is >> addr; - if (! is.fail() && is.rdbuf()->in_avail() == 0) - return std::make_pair (addr, true); - return std::make_pair (Address (), false); -} - -std::string Address::to_string () const -{ - return (is_v4 ()) - ? IP::to_string (to_v4()) - : IP::to_string (to_v6()); -} - -AddressV4 const& Address::to_v4 () const -{ - if (m_type != ipv4) - throw std::bad_cast(); - return m_v4; -} - -AddressV6 const& Address::to_v6 () const -{ - if (m_type != ipv6) - throw std::bad_cast(); - return m_v6; -} - -bool operator== (Address const& lhs, Address const& rhs) -{ - if (lhs.is_v4 ()) - { - if (rhs.is_v4 ()) - return lhs.to_v4() == rhs.to_v4(); - } - else - { - if (rhs.is_v6 ()) - return lhs.to_v6() == rhs.to_v6(); - } - - return false; -} - -bool operator< (Address const& lhs, Address const& rhs) -{ - if (lhs.m_type < rhs.m_type) - return true; - if (lhs.is_v4 ()) - return lhs.to_v4() < rhs.to_v4(); - return lhs.to_v6() < rhs.to_v6(); -} - -//------------------------------------------------------------------------------ - -bool is_loopback (Address const& addr) -{ - return (addr.is_v4 ()) - ? is_loopback (addr.to_v4 ()) - : is_loopback (addr.to_v6 ()); -} - -bool is_unspecified (Address const& addr) -{ - return (addr.is_v4 ()) - ? is_unspecified (addr.to_v4 ()) - : is_unspecified (addr.to_v6 ()); -} - -bool is_multicast (Address const& addr) -{ - return (addr.is_v4 ()) - ? is_multicast (addr.to_v4 ()) - : is_multicast (addr.to_v6 ()); -} - -bool is_private (Address const& addr) -{ - return (addr.is_v4 ()) - ? is_private (addr.to_v4 ()) - : is_private (addr.to_v6 ()); -} - -bool is_public (Address const& addr) -{ - return (addr.is_v4 ()) - ? is_public (addr.to_v4 ()) - : is_public (addr.to_v6 ()); -} - -//------------------------------------------------------------------------------ - -std::size_t hash_value (Address const& addr) -{ - return (addr.is_v4 ()) - ? hash_value (addr.to_v4()) - : hash_value (addr.to_v6()); -} - -std::istream& operator>> (std::istream& is, Address& addr) -{ - // VFALCO TODO Support ipv6! - AddressV4 addrv4; - is >> addrv4; - addr = Address (addrv4); - return is; -} - //------------------------------------------------------------------------------ class IPAddressTests : public UnitTest diff --git a/beast/threads/LockGuard.h b/beast/threads/LockGuard.h deleted file mode 100644 index a90895ae0..000000000 --- a/beast/threads/LockGuard.h +++ /dev/null @@ -1,50 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_THREADS_LOCKGUARD_H_INCLUDED -#define BEAST_THREADS_LOCKGUARD_H_INCLUDED - -#include "../Uncopyable.h" - -namespace beast { - -template -class LockGuard : public Uncopyable -{ -public: - typedef Mutex MutexType; - - explicit LockGuard (Mutex const& mutex) - : m_mutex (mutex) - { - m_mutex.lock(); - } - - ~LockGuard () - { - m_mutex.unlock(); - } - -private: - Mutex const& m_mutex; -}; - -} - -#endif diff --git a/beast/threads/RecursiveMutex.h b/beast/threads/RecursiveMutex.h index 15a233058..3f7cb59ab 100644 --- a/beast/threads/RecursiveMutex.h +++ b/beast/threads/RecursiveMutex.h @@ -25,10 +25,11 @@ #define BEAST_THREADS_RECURSIVEMUTEX_H_INCLUDED #include "../Config.h" -#include "LockGuard.h" #include "UnlockGuard.h" #include "TryLockGuard.h" +#include + #if ! BEAST_WINDOWS #include #endif @@ -38,7 +39,7 @@ namespace beast { class RecursiveMutex { public: - typedef LockGuard ScopedLockType; + typedef std::lock_guard ScopedLockType; typedef UnlockGuard ScopedUnlockType; typedef TryLockGuard ScopedTryLockType; diff --git a/beast/threads/ScopedWrapperContext.h b/beast/threads/ScopedWrapperContext.h index 6a0b88324..b8094bfdf 100644 --- a/beast/threads/ScopedWrapperContext.h +++ b/beast/threads/ScopedWrapperContext.h @@ -30,19 +30,20 @@ template class ScopedWrapper { public: - ScopedWrapper (Context const& context, Handler const& handler) + ScopedWrapper (Context& context, Handler const& handler) : m_context (context) , m_handler (handler) - { } + { + } void operator() () { - ScopedType const scope (m_context); + ScopedType scope (m_context); m_handler(); } private: - Context const& m_context; + Context& m_context; Handler m_handler; }; @@ -55,17 +56,19 @@ template class ScopedWrapperContext { public: - typedef Context context_type; - typedef ScopedType scoped_type; + typedef Context context_type; + typedef ScopedType scoped_type; class Scope { public: explicit Scope (ScopedWrapperContext const& owner) : m_scope (owner.m_context) - { } + { + } + private: - scoped_type m_scope; + scoped_type mutable m_scope; }; ScopedWrapperContext () @@ -74,7 +77,8 @@ public: template explicit ScopedWrapperContext (Arg& arg) : m_context (arg) - { } + { + } template detail::ScopedWrapper wrap ( @@ -85,7 +89,7 @@ public: } private: - Context m_context; + Context mutable m_context; }; } diff --git a/beast/threads/SharedMutexAdapter.h b/beast/threads/SharedMutexAdapter.h index cb28ea51a..8147dc3a1 100644 --- a/beast/threads/SharedMutexAdapter.h +++ b/beast/threads/SharedMutexAdapter.h @@ -20,9 +20,10 @@ #ifndef BEAST_THREADS_SHAREDMUTEXADAPTER_H_INCLUDED #define BEAST_THREADS_SHAREDMUTEXADAPTER_H_INCLUDED -#include "LockGuard.h" #include "SharedLockGuard.h" +#include + namespace beast { /** Adapts a regular Lockable to conform to the SharedMutex concept. @@ -35,7 +36,7 @@ class SharedMutexAdapter { public: typedef Mutex MutexType; - typedef LockGuard LockGuardType; + typedef std::lock_guard LockGuardType; typedef SharedLockGuard SharedLockGuardType; void lock() const diff --git a/beast/threads/SpinLock.h b/beast/threads/SpinLock.h index cbc6e0e95..88e21fcdb 100644 --- a/beast/threads/SpinLock.h +++ b/beast/threads/SpinLock.h @@ -25,9 +25,10 @@ #define BEAST_THREADS_SPINLOCK_H_INCLUDED #include "../Atomic.h" -#include "LockGuard.h" #include "UnlockGuard.h" +#include + namespace beast { //============================================================================== @@ -47,7 +48,7 @@ class BEAST_API SpinLock : public Uncopyable { public: /** Provides the type of scoped lock to use for locking a SpinLock. */ - typedef LockGuard ScopedLockType; + typedef std::lock_guard ScopedLockType; /** Provides the type of scoped unlocker to use with a SpinLock. */ typedef UnlockGuard ScopedUnlockType; diff --git a/beast/threads/ThreadLocalValue.h b/beast/threads/ThreadLocalValue.h index 751062efe..ac8310cd1 100644 --- a/beast/threads/ThreadLocalValue.h +++ b/beast/threads/ThreadLocalValue.h @@ -187,8 +187,8 @@ private: Type object; }; - mutable Atomic first; - SpinLock lock; + Atomic mutable first; + SpinLock mutable lock; #endif }; diff --git a/beast/type_traits/maybe_const.h b/beast/type_traits/maybe_const.h index b72d08e72..95c136b54 100644 --- a/beast/type_traits/maybe_const.h +++ b/beast/type_traits/maybe_const.h @@ -33,6 +33,10 @@ struct maybe_const typename std::remove_const ::type>::type type; }; +/** Alias for omitting `typename`. */ +template +using maybe_const_t = typename maybe_const ::type; + } #endif diff --git a/beast/utility/Error.h b/beast/utility/Error.h index f9b188925..0c095bfc2 100644 --- a/beast/utility/Error.h +++ b/beast/utility/Error.h @@ -22,7 +22,6 @@ #include "../Config.h" -#include "../SafeBool.h" #include "../strings/String.h" #include @@ -43,7 +42,6 @@ namespace beast { */ class Error : public std::exception - , public SafeBool { public: /** Numeric code. @@ -88,7 +86,10 @@ public: Code code () const; bool failed () const; - bool asBoolean () const; + explicit operator bool () const + { + return code () != success; + } String const getReasonText () const; String const getSourceFilename () const; diff --git a/beast/utility/Journal.h b/beast/utility/Journal.h index d052a59ab..c0782d360 100644 --- a/beast/utility/Journal.h +++ b/beast/utility/Journal.h @@ -20,8 +20,6 @@ #ifndef BEAST_UTILITY_JOURNAL_H_INCLUDED #define BEAST_UTILITY_JOURNAL_H_INCLUDED -#include "../SafeBool.h" - #include namespace beast { @@ -150,7 +148,7 @@ public: //-------------------------------------------------------------------------- - class Stream : public SafeBool + class Stream { public: /** Create a stream which produces no output. */ @@ -177,7 +175,12 @@ public: /** Returns `true` if sink logs anything at this stream's severity. */ /** @{ */ bool active() const; - bool asBoolean() const; + + explicit + operator bool() const + { + return ! m_disabled; + } /** @} */ /** Output stream support. */ diff --git a/beast/utility/impl/Error.cpp b/beast/utility/impl/Error.cpp index 9083413fe..7751c4176 100644 --- a/beast/utility/impl/Error.cpp +++ b/beast/utility/impl/Error.cpp @@ -81,11 +81,6 @@ bool Error::failed () const return code () != success; } -bool Error::asBoolean () const -{ - return code () != success; -} - String const Error::getReasonText () const { return m_reasonText; diff --git a/beast/utility/impl/Journal.cpp b/beast/utility/impl/Journal.cpp index ed115b07c..42dd56273 100644 --- a/beast/utility/impl/Journal.cpp +++ b/beast/utility/impl/Journal.cpp @@ -211,11 +211,6 @@ bool Journal::Stream::active () const return ! m_disabled && m_sink->active (m_level); } -bool Journal::Stream::asBoolean () const -{ - return active(); -} - Journal::Stream& Journal::Stream::operator= (Stream const& other) { m_sink = other.m_sink; diff --git a/modules/beast_asio/protocol/InputParser.h b/modules/beast_asio/protocol/InputParser.h index 9ab0a0248..97962b7ef 100644 --- a/modules/beast_asio/protocol/InputParser.h +++ b/modules/beast_asio/protocol/InputParser.h @@ -30,7 +30,7 @@ namespace InputParser { Or you can use stop() to decide if you should return. After a stop you can use failed () to determine if parsing failed. */ -struct State : SafeBool +struct State { enum State_t { @@ -54,7 +54,7 @@ struct State : SafeBool bool stop () const noexcept { return m_state != pass; } bool passed () const noexcept { return m_state == pass; } bool failed () const noexcept { return m_state == fail; } - bool asBoolean () const noexcept { return m_state == pass; } // for SafeBool<> + explicit operator bool() const noexcept { return m_state == pass; } private: State_t m_state; diff --git a/modules/beast_core/beast_core.cpp b/modules/beast_core/beast_core.cpp index 156cf509c..37a36b738 100644 --- a/modules/beast_core/beast_core.cpp +++ b/modules/beast_core/beast_core.cpp @@ -163,7 +163,6 @@ namespace beast #include "misc/Uuid.cpp" #include "network/MACAddress.cpp" -#include "network/NamedPipe.cpp" #include "network/Socket.cpp" #include "streams/BufferedInputStream.cpp" @@ -188,7 +187,6 @@ namespace beast #include "thread/Workers.cpp" #include "threads/ChildProcess.cpp" -#include "threads/ReadWriteLock.cpp" #include "threads/SpinDelay.cpp" #include "time/PerformanceCounter.cpp" @@ -218,7 +216,6 @@ namespace beast #if ! BEAST_WINDOWS #include "native/posix_SharedCode.h" -#include "native/posix_NamedPipe.cpp" #endif #if BEAST_MAC || BEAST_IOS diff --git a/modules/beast_core/beast_core.h b/modules/beast_core/beast_core.h index de35a6be8..a5d6ab17c 100644 --- a/modules/beast_core/beast_core.h +++ b/modules/beast_core/beast_core.h @@ -55,7 +55,6 @@ #include "../../beast/Memory.h" #include "../../beast/Intrusive.h" #include "../../beast/Net.h" -#include "../../beast/SafeBool.h" #include "../../beast/Strings.h" #include "../../beast/TypeTraits.h" #include "../../beast/Threads.h" @@ -181,8 +180,6 @@ class FileOutputStream; #include "misc/Uuid.h" #include "misc/WindowsRegistry.h" #include "network/MACAddress.h" -#include "threads/ReadWriteLock.h" -#include "network/NamedPipe.h" #include "network/Socket.h" #include "streams/BufferedInputStream.h" #include "streams/MemoryInputStream.h" @@ -198,8 +195,6 @@ class FileOutputStream; #include "threads/HighResolutionTimer.h" #include "threads/InterProcessLock.h" #include "threads/Process.h" -#include "threads/ScopedReadLock.h" -#include "threads/ScopedWriteLock.h" #include "diagnostic/UnitTest.h" #include "xml/XmlDocument.h" #include "xml/XmlElement.h" diff --git a/modules/beast_core/diagnostic/UnitTest.cpp b/modules/beast_core/diagnostic/UnitTest.cpp index 94d74f5d2..5d94ab60b 100644 --- a/modules/beast_core/diagnostic/UnitTest.cpp +++ b/modules/beast_core/diagnostic/UnitTest.cpp @@ -130,7 +130,7 @@ void UnitTest::beginTestCase (String const& name) m_case = new Case (name, m_className); } -bool UnitTest::expect (bool trueCondition, String const& failureMessage) +bool UnitTest::expect_bool (bool trueCondition, String const& failureMessage) { if (trueCondition) { @@ -144,7 +144,7 @@ bool UnitTest::expect (bool trueCondition, String const& failureMessage) return trueCondition; } -bool UnitTest::unexpected (bool falseCondition, String const& failureMessage) +bool UnitTest::unexpected_bool (bool falseCondition, String const& failureMessage) { return expect (! falseCondition, failureMessage); } diff --git a/modules/beast_core/diagnostic/UnitTest.h b/modules/beast_core/diagnostic/UnitTest.h index 02dc832b0..71c3091bf 100644 --- a/modules/beast_core/diagnostic/UnitTest.h +++ b/modules/beast_core/diagnostic/UnitTest.h @@ -266,17 +266,35 @@ public: If Suite is true, a pass is logged; if it's false, a failure is logged. If the failure message is specified, it will be written to the log if the test fails. + + Requirements: + Condition must be explicitly convertible to bool */ - bool expect (bool trueCondition, String const& failureMessage = String::empty); + template + bool expect (Condition trueCondition, String const& failureMessage = String::empty) + { + return expect_bool (!!trueCondition, failureMessage); + } + + bool expect_bool (bool trueCondition, String const& failureMessage); /** Checks that the result of a test is false, and logs this result. This is basically the opposite of expect(). @see expect - */ - bool unexpected (bool falseCondition, String const& failureMessage = String::empty); + Requirements: + Condition must be explicitly convertible to bool + */ + template + bool unexpected (Condition falseCondition, String const& failureMessage = String::empty) + { + return unexpected_bool (!!falseCondition, failureMessage); + } + + bool unexpected_bool (bool falseCondition, String const& failureMessage); + /** Compares two values, and if they don't match, prints out a message containing the expected and actual result values. */ diff --git a/modules/beast_core/native/posix_NamedPipe.cpp b/modules/beast_core/native/posix_NamedPipe.cpp deleted file mode 100644 index 227dbc79e..000000000 --- a/modules/beast_core/native/posix_NamedPipe.cpp +++ /dev/null @@ -1,212 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -class NamedPipe::Pimpl : LeakChecked , public Uncopyable -{ -public: - Pimpl (const String& pipePath, bool createPipe) - : pipeInName (pipePath + "_in"), - pipeOutName (pipePath + "_out"), - pipeIn (-1), pipeOut (-1), - createdPipe (createPipe), - stopReadOperation (false) - { - signal (SIGPIPE, signalHandler); - beast_siginterrupt (SIGPIPE, 1); - } - - ~Pimpl() - { - if (pipeIn != -1) ::close (pipeIn); - if (pipeOut != -1) ::close (pipeOut); - - if (createdPipe) - { - unlink (pipeInName.toUTF8()); - unlink (pipeOutName.toUTF8()); - } - } - - int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds) - { - const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds); - - if (pipeIn == -1) - { - pipeIn = openPipe (createdPipe ? pipeInName : pipeOutName, O_RDWR | O_NONBLOCK, timeoutEnd); - - if (pipeIn == -1) - return -1; - } - - int bytesRead = 0; - - while (bytesRead < maxBytesToRead) - { - const int bytesThisTime = maxBytesToRead - bytesRead; - const int numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime); - - if (numRead <= 0) - { - if (errno != EWOULDBLOCK || stopReadOperation || hasExpired (timeoutEnd)) - return -1; - - const int maxWaitingTime = 30; - waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime - : bmin (maxWaitingTime, - (int) (timeoutEnd - Time::getMillisecondCounter()))); - continue; - } - - bytesRead += numRead; - destBuffer += numRead; - } - - return bytesRead; - } - - int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds) - { - const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds); - - if (pipeOut == -1) - { - pipeOut = openPipe (createdPipe ? pipeOutName : pipeInName, O_WRONLY, timeoutEnd); - - if (pipeOut == -1) - return -1; - } - - int bytesWritten = 0; - - while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd)) - { - const int bytesThisTime = numBytesToWrite - bytesWritten; - const int numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime); - - if (numWritten <= 0) - return -1; - - bytesWritten += numWritten; - sourceBuffer += numWritten; - } - - return bytesWritten; - } - - bool createFifos() const - { - return (mkfifo (pipeInName .toUTF8(), 0666) == 0 || errno == EEXIST) - && (mkfifo (pipeOutName.toUTF8(), 0666) == 0 || errno == EEXIST); - } - - const String pipeInName, pipeOutName; - int pipeIn, pipeOut; - - const bool createdPipe; - bool stopReadOperation; - -private: - static void signalHandler (int) {} - - static uint32 getTimeoutEnd (const int timeOutMilliseconds) - { - return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0; - } - - static bool hasExpired (const uint32 timeoutEnd) - { - return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd; - } - - int openPipe (const String& name, int flags, const uint32 timeoutEnd) - { - for (;;) - { - const int p = ::open (name.toUTF8(), flags); - - if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation) - return p; - - Thread::sleep (2); - } - } - - static void waitForInput (const int handle, const int timeoutMsecs) noexcept - { - struct timeval timeout; - timeout.tv_sec = timeoutMsecs / 1000; - timeout.tv_usec = (timeoutMsecs % 1000) * 1000; - - fd_set rset; - FD_ZERO (&rset); - FD_SET (handle, &rset); - - select (handle + 1, &rset, nullptr, 0, &timeout); - } -}; - -void NamedPipe::close() -{ - if (pimpl != nullptr) - { - pimpl->stopReadOperation = true; - - char buffer[1] = { 0 }; - ssize_t done = ::write (pimpl->pipeIn, buffer, 1); - (void) done; - - ScopedWriteLock sl (lock); - pimpl = nullptr; - } -} - -bool NamedPipe::openInternal (const String& pipeName, const bool createPipe) -{ - #if BEAST_IOS - pimpl = new Pimpl (File::getSpecialLocation (File::tempDirectory) - .getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe); - #else - pimpl = new Pimpl ("/tmp/" + File::createLegalFileName (pipeName), createPipe); - #endif - - if (createPipe && ! pimpl->createFifos()) - { - pimpl = nullptr; - return false; - } - - return true; -} - -int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds) -{ - ScopedReadLock sl (lock); - return pimpl != nullptr ? pimpl->read (static_cast (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1; -} - -int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds) -{ - ScopedReadLock sl (lock); - return pimpl != nullptr ? pimpl->write (static_cast (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1; -} diff --git a/modules/beast_core/native/win32_Files.cpp b/modules/beast_core/native/win32_Files.cpp index e3952b82a..5767925b5 100644 --- a/modules/beast_core/native/win32_Files.cpp +++ b/modules/beast_core/native/win32_Files.cpp @@ -883,226 +883,3 @@ void File::revealToUser() const } } } - -//============================================================================== -class NamedPipe::Pimpl : LeakChecked , public Uncopyable -{ -public: - Pimpl (const String& pipeName, const bool createPipe) - : filename ("\\\\.\\pipe\\" + File::createLegalFileName (pipeName)), - pipeH (INVALID_HANDLE_VALUE), - cancelEvent (CreateEvent (0, FALSE, FALSE, 0)), - connected (false), ownsPipe (createPipe), shouldStop (false) - { - if (createPipe) - pipeH = CreateNamedPipe (filename.toWideCharPointer(), - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, - PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0); - } - - ~Pimpl() - { - disconnectPipe(); - - if (pipeH != INVALID_HANDLE_VALUE) - CloseHandle (pipeH); - - CloseHandle (cancelEvent); - } - - bool connect (const int timeOutMs) - { - if (! ownsPipe) - { - if (pipeH != INVALID_HANDLE_VALUE) - return true; - - const Time timeOutEnd (Time::getCurrentTime() + RelativeTime::milliseconds (timeOutMs)); - - for (;;) - { - { - const ScopedLock sl (createFileLock); - - if (pipeH == INVALID_HANDLE_VALUE) - pipeH = CreateFile (filename.toWideCharPointer(), - GENERIC_READ | GENERIC_WRITE, 0, 0, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - } - - if (pipeH != INVALID_HANDLE_VALUE) - return true; - - if (shouldStop || (timeOutMs >= 0 && Time::getCurrentTime() > timeOutEnd)) - return false; - - Thread::sleep (1); - } - } - - if (! connected) - { - OverlappedEvent over; - - if (ConnectNamedPipe (pipeH, &over.over) == 0) - { - switch (GetLastError()) - { - case ERROR_PIPE_CONNECTED: connected = true; break; - case ERROR_IO_PENDING: - case ERROR_PIPE_LISTENING: connected = waitForIO (over, timeOutMs); break; - default: break; - } - } - } - - return connected; - } - - void disconnectPipe() - { - if (ownsPipe && connected) - { - DisconnectNamedPipe (pipeH); - connected = false; - } - } - - int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds) - { - while (connect (timeOutMilliseconds)) - { - if (maxBytesToRead <= 0) - return 0; - - OverlappedEvent over; - unsigned long numRead; - - if (ReadFile (pipeH, destBuffer, (DWORD) maxBytesToRead, &numRead, &over.over)) - return (int) numRead; - - const DWORD lastError = GetLastError(); - - if (lastError == ERROR_IO_PENDING) - { - if (! waitForIO (over, timeOutMilliseconds)) - return -1; - - if (GetOverlappedResult (pipeH, &over.over, &numRead, FALSE)) - return (int) numRead; - } - - if (ownsPipe && (GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_PIPE_NOT_CONNECTED)) - disconnectPipe(); - else - break; - } - - return -1; - } - - int write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds) - { - if (connect (timeOutMilliseconds)) - { - if (numBytesToWrite <= 0) - return 0; - - OverlappedEvent over; - unsigned long numWritten; - - if (WriteFile (pipeH, sourceBuffer, (DWORD) numBytesToWrite, &numWritten, &over.over)) - return (int) numWritten; - - if (GetLastError() == ERROR_IO_PENDING) - { - if (! waitForIO (over, timeOutMilliseconds)) - return -1; - - if (GetOverlappedResult (pipeH, &over.over, &numWritten, FALSE)) - return (int) numWritten; - - if (GetLastError() == ERROR_BROKEN_PIPE && ownsPipe) - disconnectPipe(); - } - } - - return -1; - } - - const String filename; - HANDLE pipeH, cancelEvent; - bool connected, ownsPipe, shouldStop; - CriticalSection createFileLock; - -private: - struct OverlappedEvent - { - OverlappedEvent() - { - zerostruct (over); - over.hEvent = CreateEvent (0, TRUE, FALSE, 0); - } - - ~OverlappedEvent() - { - CloseHandle (over.hEvent); - } - - OVERLAPPED over; - }; - - bool waitForIO (OverlappedEvent& over, int timeOutMilliseconds) - { - if (shouldStop) - return false; - - HANDLE handles[] = { over.over.hEvent, cancelEvent }; - DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE, - timeOutMilliseconds >= 0 ? timeOutMilliseconds - : INFINITE); - - if (waitResult == WAIT_OBJECT_0) - return true; - - CancelIo (pipeH); - return false; - } -}; - -void NamedPipe::close() -{ - if (pimpl != nullptr) - { - pimpl->shouldStop = true; - SetEvent (pimpl->cancelEvent); - - ScopedWriteLock sl (lock); - pimpl = nullptr; - } -} - -bool NamedPipe::openInternal (const String& pipeName, const bool createPipe) -{ - pimpl = new Pimpl (pipeName, createPipe); - - if (createPipe && pimpl->pipeH == INVALID_HANDLE_VALUE) - { - pimpl = nullptr; - return false; - } - - return true; -} - -int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds) -{ - ScopedReadLock sl (lock); - return pimpl != nullptr ? pimpl->read (destBuffer, maxBytesToRead, timeOutMilliseconds) : -1; -} - -int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds) -{ - ScopedReadLock sl (lock); - return pimpl != nullptr ? pimpl->write (sourceBuffer, numBytesToWrite, timeOutMilliseconds) : -1; -} diff --git a/modules/beast_core/thread/impl/TrackedMutex.cpp b/modules/beast_core/thread/impl/TrackedMutex.cpp index 98da8cf0d..0978d402a 100644 --- a/modules/beast_core/thread/impl/TrackedMutex.cpp +++ b/modules/beast_core/thread/impl/TrackedMutex.cpp @@ -112,7 +112,7 @@ bool TrackedMutex::Record::isNotNull () const noexcept return m_mutexName != ""; } -bool TrackedMutex::Record::asBoolean () const noexcept +TrackedMutex::Record::operator bool() const noexcept { return isNotNull (); } @@ -170,7 +170,7 @@ bool TrackedMutex::Agent::isNotNull () const noexcept return m_thread != nullptr; } -bool TrackedMutex::Agent::asBoolean () const noexcept +TrackedMutex::Agent::operator bool() const noexcept { return isNotNull (); } diff --git a/modules/beast_core/thread/impl/TrackedMutex.h b/modules/beast_core/thread/impl/TrackedMutex.h index 783c2014d..30e797f28 100644 --- a/modules/beast_core/thread/impl/TrackedMutex.h +++ b/modules/beast_core/thread/impl/TrackedMutex.h @@ -32,7 +32,7 @@ public: /** A triplet identifying a mutex, a thread, and source code location. */ - class Record : public SafeBool + class Record { public: Record () noexcept; @@ -41,7 +41,7 @@ public: bool isNull () const noexcept; bool isNotNull () const noexcept; - bool asBoolean () const noexcept; + explicit operator bool() const noexcept; /** Returns the name of the mutex. Since the Mutex may not exist after the Record record is @@ -76,7 +76,7 @@ public: //-------------------------------------------------------------------------- /** Describes a thread that can acquire mutexes. */ - class Agent : public SafeBool + class Agent { public: Agent () noexcept; @@ -85,7 +85,7 @@ public: bool isNull () const noexcept; bool isNotNull () const noexcept; - bool asBoolean () const noexcept; + explicit operator bool() const noexcept; /** Returns the name of the thread. The name is generated at the time the Agent record is created, diff --git a/modules/beast_core/threads/ReadWriteLock.cpp b/modules/beast_core/threads/ReadWriteLock.cpp deleted file mode 100644 index fbc784a24..000000000 --- a/modules/beast_core/threads/ReadWriteLock.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -ReadWriteLock::ReadWriteLock() noexcept - : numWaitingWriters (0), - numWriters (0), - writerThreadId (0) -{ - readerThreads.ensureStorageAllocated (16); -} - -ReadWriteLock::~ReadWriteLock() noexcept -{ - bassert (readerThreads.size() == 0); - bassert (numWriters == 0); -} - -//============================================================================== -void ReadWriteLock::enterRead() const noexcept -{ - while (! tryEnterRead()) - waitEvent.wait (100); -} - -bool ReadWriteLock::tryEnterRead() const noexcept -{ - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); - - const SpinLock::ScopedLockType sl (accessLock); - - for (int i = 0; i < readerThreads.size(); ++i) - { - ThreadRecursionCount& trc = readerThreads.getReference(i); - - if (trc.threadID == threadId) - { - trc.count++; - return true; - } - } - - if (numWriters + numWaitingWriters == 0 - || (threadId == writerThreadId && numWriters > 0)) - { - ThreadRecursionCount trc = { threadId, 1 }; - readerThreads.add (trc); - return true; - } - - return false; -} - -void ReadWriteLock::exitRead() const noexcept -{ - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); - const SpinLock::ScopedLockType sl (accessLock); - - for (int i = 0; i < readerThreads.size(); ++i) - { - ThreadRecursionCount& trc = readerThreads.getReference(i); - - if (trc.threadID == threadId) - { - if (--(trc.count) == 0) - { - readerThreads.remove (i); - waitEvent.signal(); - } - - return; - } - } - - bassertfalse; // unlocking a lock that wasn't locked.. -} - -//============================================================================== -void ReadWriteLock::enterWrite() const noexcept -{ - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); - const SpinLock::ScopedLockType sl (accessLock); - - for (;;) - { - if (readerThreads.size() + numWriters == 0 - || threadId == writerThreadId - || (readerThreads.size() == 1 - && readerThreads.getReference(0).threadID == threadId)) - { - writerThreadId = threadId; - ++numWriters; - break; - } - - ++numWaitingWriters; - accessLock.exit(); - waitEvent.wait (100); - accessLock.enter(); - --numWaitingWriters; - } -} - -bool ReadWriteLock::tryEnterWrite() const noexcept -{ - const Thread::ThreadID threadId = Thread::getCurrentThreadId(); - const SpinLock::ScopedLockType sl (accessLock); - - if (readerThreads.size() + numWriters == 0 - || threadId == writerThreadId - || (readerThreads.size() == 1 - && readerThreads.getReference(0).threadID == threadId)) - { - writerThreadId = threadId; - ++numWriters; - return true; - } - - return false; -} - -void ReadWriteLock::exitWrite() const noexcept -{ - const SpinLock::ScopedLockType sl (accessLock); - - // check this thread actually had the lock.. - bassert (numWriters > 0 && writerThreadId == Thread::getCurrentThreadId()); - - if (--numWriters == 0) - { - writerThreadId = 0; - waitEvent.signal(); - } -} diff --git a/modules/beast_core/threads/ReadWriteLock.h b/modules/beast_core/threads/ReadWriteLock.h deleted file mode 100644 index e1c0442f9..000000000 --- a/modules/beast_core/threads/ReadWriteLock.h +++ /dev/null @@ -1,145 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_READWRITELOCK_H_INCLUDED -#define BEAST_READWRITELOCK_H_INCLUDED - -//============================================================================== -/** - A critical section that allows multiple simultaneous readers. - - Features of this type of lock are: - - - Multiple readers can hold the lock at the same time, but only one writer - can hold it at once. - - Writers trying to gain the lock will be blocked until all readers and writers - have released it - - Readers trying to gain the lock while a writer is waiting to acquire it will be - blocked until the writer has obtained and released it - - If a thread already has a read lock and tries to obtain a write lock, it will succeed if - there are no other readers - - If a thread already has the write lock and tries to obtain a read lock, this will succeed. - - Recursive locking is supported. - - @see ScopedReadLock, ScopedWriteLock, CriticalSection -*/ -class BEAST_API ReadWriteLock : public Uncopyable -{ -public: - //============================================================================== - /** - Creates a ReadWriteLock object. - */ - ReadWriteLock() noexcept; - - /** Destructor. - - If the object is deleted whilst locked, any subsequent behaviour - is unpredictable. - */ - ~ReadWriteLock() noexcept; - - //============================================================================== - /** Locks this object for reading. - - Multiple threads can simulaneously lock the object for reading, but if another - thread has it locked for writing, then this will block until it releases the - lock. - - @see exitRead, ScopedReadLock - */ - void enterRead() const noexcept; - - /** Tries to lock this object for reading. - - Multiple threads can simulaneously lock the object for reading, but if another - thread has it locked for writing, then this will fail and return false. - - @returns true if the lock is successfully gained. - @see exitRead, ScopedReadLock - */ - bool tryEnterRead() const noexcept; - - /** Releases the read-lock. - - If the caller thread hasn't got the lock, this can have unpredictable results. - - If the enterRead() method has been called multiple times by the thread, each - call must be matched by a call to exitRead() before other threads will be allowed - to take over the lock. - - @see enterRead, ScopedReadLock - */ - void exitRead() const noexcept; - - //============================================================================== - /** Locks this object for writing. - - This will block until any other threads that have it locked for reading or - writing have released their lock. - - @see exitWrite, ScopedWriteLock - */ - void enterWrite() const noexcept; - - /** Tries to lock this object for writing. - - This is like enterWrite(), but doesn't block - it returns true if it manages - to obtain the lock. - - @returns true if the lock is successfully gained. - @see enterWrite - */ - bool tryEnterWrite() const noexcept; - - /** Releases the write-lock. - - If the caller thread hasn't got the lock, this can have unpredictable results. - - If the enterWrite() method has been called multiple times by the thread, each - call must be matched by a call to exit() before other threads will be allowed - to take over the lock. - - @see enterWrite, ScopedWriteLock - */ - void exitWrite() const noexcept; - - -private: - //============================================================================== - SpinLock accessLock; - WaitableEvent waitEvent; - mutable int numWaitingWriters, numWriters; - mutable Thread::ThreadID writerThreadId; - - struct ThreadRecursionCount - { - Thread::ThreadID threadID; - int count; - }; - - mutable Array readerThreads; -}; - - -#endif // BEAST_READWRITELOCK_H_INCLUDED diff --git a/modules/beast_core/threads/ScopedReadLock.h b/modules/beast_core/threads/ScopedReadLock.h deleted file mode 100644 index e20b83980..000000000 --- a/modules/beast_core/threads/ScopedReadLock.h +++ /dev/null @@ -1,82 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_SCOPEDREADLOCK_H_INCLUDED -#define BEAST_SCOPEDREADLOCK_H_INCLUDED - -//============================================================================== -/** - Automatically locks and unlocks a ReadWriteLock object. - - Use one of these as a local variable to control access to a ReadWriteLock. - - e.g. @code - - ReadWriteLock myLock; - - for (;;) - { - const ScopedReadLock myScopedLock (myLock); - // myLock is now locked - - ...do some stuff... - - // myLock gets unlocked here. - } - @endcode - - @see ReadWriteLock, ScopedWriteLock -*/ -class BEAST_API ScopedReadLock : public Uncopyable -{ -public: - //============================================================================== - /** Creates a ScopedReadLock. - - As soon as it is created, this will call ReadWriteLock::enterRead(), and - when the ScopedReadLock object is deleted, the ReadWriteLock will - be unlocked. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. - */ - inline explicit ScopedReadLock (const ReadWriteLock& lock) noexcept : lock_ (lock) { lock.enterRead(); } - - /** Destructor. - - The ReadWriteLock's exitRead() method will be called when the destructor is called. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - inline ~ScopedReadLock() noexcept { lock_.exitRead(); } - - -private: - //============================================================================== - const ReadWriteLock& lock_; -}; - - -#endif // BEAST_SCOPEDREADLOCK_H_INCLUDED diff --git a/modules/beast_core/threads/ScopedWriteLock.h b/modules/beast_core/threads/ScopedWriteLock.h deleted file mode 100644 index 9d03482f0..000000000 --- a/modules/beast_core/threads/ScopedWriteLock.h +++ /dev/null @@ -1,82 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_SCOPEDWRITELOCK_H_INCLUDED -#define BEAST_SCOPEDWRITELOCK_H_INCLUDED - -//============================================================================== -/** - Automatically locks and unlocks a ReadWriteLock object. - - Use one of these as a local variable to control access to a ReadWriteLock. - - e.g. @code - - ReadWriteLock myLock; - - for (;;) - { - const ScopedWriteLock myScopedLock (myLock); - // myLock is now locked - - ...do some stuff... - - // myLock gets unlocked here. - } - @endcode - - @see ReadWriteLock, ScopedReadLock -*/ -class BEAST_API ScopedWriteLock : public Uncopyable -{ -public: - //============================================================================== - /** Creates a ScopedWriteLock. - - As soon as it is created, this will call ReadWriteLock::enterWrite(), and - when the ScopedWriteLock object is deleted, the ReadWriteLock will - be unlocked. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating one with the new() operator. - */ - inline explicit ScopedWriteLock (const ReadWriteLock& lock) noexcept : lock_ (lock) { lock.enterWrite(); } - - /** Destructor. - - The ReadWriteLock's exitWrite() method will be called when the destructor is called. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - inline ~ScopedWriteLock() noexcept { lock_.exitWrite(); } - - -private: - //============================================================================== - const ReadWriteLock& lock_; -}; - - -#endif // BEAST_SCOPEDWRITELOCK_H_INCLUDED