beast, beast::asio improvements and fixes:

* New maybe_const_t alias for maybe_const
* New asio::enable_wait_for_async for safe cleanup
* New asio::memory_buffer, a managed boost::asio compatible buffer
* shared_handler improvements:
   - Can be 'empty' (no stored handler).
   - Default constructible as 'empty'.
   - Safe evaluation in bool contexts, false==empty
* Fix is_call_possible metafunction:
   - Works on empty argument lists
   - Works with reference types
* Replace SafeBool idiom with C++11 explicit operator bool
* Move IPAddress function definitions to the header
* Move cyclic_iterator to container/
* Remove unused BufferType
* Remove obsolete classes:
   - NamedPipe
   - ReadWriteLock
   - ScopedReadLock
   - ScopedWriteLock
   - LockGuard
This commit is contained in:
Vinnie Falco
2014-03-16 20:32:14 -07:00
parent 6546c30e17
commit d4a5c0353d
45 changed files with 1192 additions and 1469 deletions

View File

@@ -21,6 +21,7 @@
<ItemGroup>
<None Include="..\..\.gitattributes" />
<None Include="..\..\.gitignore" />
<None Include="..\..\beast\asio\README.md" />
<None Include="..\..\beast\crypto\impl\sha2\README" />
<None Include="..\..\beast\crypto\impl\sha2\sha2test.pl" />
<None Include="..\..\beast\http\impl\http-parser\.gitignore" />
@@ -86,8 +87,10 @@
<ClInclude Include="..\..\beast\asio\abstract_socket.h" />
<ClInclude Include="..\..\beast\asio\bind_handler.h" />
<ClInclude Include="..\..\beast\asio\buffer_sequence.h" />
<ClInclude Include="..\..\beast\asio\enable_wait_for_async.h" />
<ClInclude Include="..\..\beast\asio\io_latency_probe.h" />
<ClInclude Include="..\..\beast\asio\IPAddressConversion.h" />
<ClInclude Include="..\..\beast\asio\memory_buffer.h" />
<ClInclude Include="..\..\beast\asio\placeholders.h" />
<ClInclude Include="..\..\beast\asio\shared_handler.h" />
<ClInclude Include="..\..\beast\asio\socket_wrapper.h" />
@@ -133,6 +136,7 @@
<ClInclude Include="..\..\beast\container\aged_unordered_multimap.h" />
<ClInclude Include="..\..\beast\container\aged_unordered_multiset.h" />
<ClInclude Include="..\..\beast\container\aged_unordered_set.h" />
<ClInclude Include="..\..\beast\container\cyclic_iterator.h" />
<ClInclude Include="..\..\beast\container\detail\aged_associative_container.h" />
<ClInclude Include="..\..\beast\container\detail\aged_ordered_container.h" />
<ClInclude Include="..\..\beast\container\detail\aged_container_iterator.h" />
@@ -152,7 +156,6 @@
<ClInclude Include="..\..\beast\cxx14\memory.h" />
<ClInclude Include="..\..\beast\cxx14\type_traits.h" />
<ClInclude Include="..\..\beast\cxx14\utility.h" />
<ClInclude Include="..\..\beast\cyclic_iterator.h" />
<ClInclude Include="..\..\beast\FixedArray.h" />
<ClInclude Include="..\..\beast\HeapBlock.h" />
<ClInclude Include="..\..\beast\HTTP.h" />
@@ -185,14 +188,12 @@
<ClInclude Include="..\..\beast\MPL.h" />
<ClInclude Include="..\..\beast\mpl\IsCallPossible.h" />
<ClInclude Include="..\..\beast\Net.h" />
<ClInclude Include="..\..\beast\net\BufferType.h" />
<ClInclude Include="..\..\beast\net\detail\Parse.h" />
<ClInclude Include="..\..\beast\net\DynamicBuffer.h" />
<ClInclude Include="..\..\beast\net\IPAddress.h" />
<ClInclude Include="..\..\beast\net\IPAddressV4.h" />
<ClInclude Include="..\..\beast\net\IPAddressV6.h" />
<ClInclude Include="..\..\beast\net\IPEndpoint.h" />
<ClInclude Include="..\..\beast\SafeBool.h" />
<ClInclude Include="..\..\beast\SmartPtr.h" />
<ClInclude Include="..\..\beast\smart_ptr\AbstractObject.h" />
<ClInclude Include="..\..\beast\smart_ptr\ContainerDeletePolicy.h" />
@@ -214,7 +215,6 @@
<ClInclude Include="..\..\beast\Chrono.h" />
<ClInclude Include="..\..\beast\threads\detail\BindHandler.h" />
<ClInclude Include="..\..\beast\threads\detail\DispatchedHandler.h" />
<ClInclude Include="..\..\beast\threads\LockGuard.h" />
<ClInclude Include="..\..\beast\threads\RecursiveMutex.h" />
<ClInclude Include="..\..\beast\threads\semaphore.h" />
<ClInclude Include="..\..\beast\threads\ServiceQueue.h" />
@@ -333,7 +333,6 @@
<ClInclude Include="..\..\modules\beast_core\native\posix_SharedCode.h" />
<ClInclude Include="..\..\modules\beast_core\native\win32_ComSmartPtr.h" />
<ClInclude Include="..\..\modules\beast_core\network\MACAddress.h" />
<ClInclude Include="..\..\modules\beast_core\network\NamedPipe.h" />
<ClInclude Include="..\..\modules\beast_core\network\Socket.h" />
<ClInclude Include="..\..\modules\beast_core\streams\BufferedInputStream.h" />
<ClInclude Include="..\..\modules\beast_core\streams\FileInputSource.h" />
@@ -362,10 +361,7 @@
<ClInclude Include="..\..\modules\beast_core\threads\HighResolutionTimer.h" />
<ClInclude Include="..\..\modules\beast_core\threads\InterProcessLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\Process.h" />
<ClInclude Include="..\..\modules\beast_core\threads\ReadWriteLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\ScopedLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\ScopedReadLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\ScopedWriteLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\SpinDelay.h" />
<ClInclude Include="..\..\modules\beast_core\thread\DeadlineTimer.h" />
<ClInclude Include="..\..\modules\beast_core\thread\Workers.h" />
@@ -433,6 +429,30 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\bind_handler_tests.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\enable_wait_for_async.test.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\shared_handler_tests.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\wrap_handler_tests.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\beast\boost\Boost.cpp" />
<ClCompile Include="..\..\beast\chrono\Chrono.cpp" />
<ClCompile Include="..\..\beast\chrono\impl\basic_seconds_clock.cpp">
@@ -1115,12 +1135,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\posix_NamedPipe.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\win32_Files.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1163,12 +1177,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\network\NamedPipe.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\network\Socket.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1277,12 +1285,6 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\threads\ReadWriteLock.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\threads\SpinDelay.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>

View File

@@ -76,6 +76,9 @@
<None Include="..\..\scripts\compile.sh">
<Filter>scripts</Filter>
</None>
<None Include="..\..\beast\asio\README.md">
<Filter>beast\asio</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Filter Include="beast_core">
@@ -309,6 +312,9 @@
<Filter Include="beast\cxx14\tests">
<UniqueIdentifier>{1271ee71-5754-46ef-845b-84e53eed11c0}</UniqueIdentifier>
</Filter>
<Filter Include="beast\asio\tests">
<UniqueIdentifier>{f2594738-6447-447b-8f51-2d42fbe8a6ee}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
@@ -419,9 +425,6 @@
<ClInclude Include="..\..\modules\beast_core\network\MACAddress.h">
<Filter>beast_core\network</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\network\NamedPipe.h">
<Filter>beast_core\network</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\network\Socket.h">
<Filter>beast_core\network</Filter>
</ClInclude>
@@ -482,18 +485,9 @@
<ClInclude Include="..\..\modules\beast_core\threads\Process.h">
<Filter>beast_core\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\threads\ReadWriteLock.h">
<Filter>beast_core\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\threads\ScopedLock.h">
<Filter>beast_core\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\threads\ScopedReadLock.h">
<Filter>beast_core\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\threads\ScopedWriteLock.h">
<Filter>beast_core\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\time\PerformanceCounter.h">
<Filter>beast_core\time</Filter>
</ClInclude>
@@ -956,9 +950,6 @@
<ClInclude Include="..\..\beast\Chrono.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\SafeBool.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\config\BeastConfig.h" />
<ClInclude Include="..\..\beast\utility\Error.h">
<Filter>beast\utility</Filter>
@@ -1014,9 +1005,6 @@
<ClInclude Include="..\..\beast\net\DynamicBuffer.h">
<Filter>beast\net</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\net\BufferType.h">
<Filter>beast\net</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\http\HTTPRequestParser.h">
<Filter>beast_asio\http</Filter>
</ClInclude>
@@ -1032,9 +1020,6 @@
<ClInclude Include="..\..\beast\Threads.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\threads\LockGuard.h">
<Filter>beast\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\threads\RecursiveMutex.h">
<Filter>beast\threads</Filter>
</ClInclude>
@@ -1149,9 +1134,6 @@
<ClInclude Include="..\..\beast\insight\HookImpl.h">
<Filter>beast\insight</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\cyclic_iterator.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\threads\semaphore.h">
<Filter>beast\threads</Filter>
</ClInclude>
@@ -1323,6 +1305,15 @@
<ClInclude Include="..\..\beast\http\impl\http_parser.h">
<Filter>beast\http\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\container\cyclic_iterator.h">
<Filter>beast\container</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\asio\enable_wait_for_async.h">
<Filter>beast\asio</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\asio\memory_buffer.h">
<Filter>beast\asio</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\containers\DynamicObject.cpp">
@@ -1406,9 +1397,6 @@
<ClCompile Include="..\..\modules\beast_core\native\linux_Threads.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\posix_NamedPipe.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\native\win32_Files.cpp">
<Filter>beast_core\native</Filter>
</ClCompile>
@@ -1427,9 +1415,6 @@
<ClCompile Include="..\..\modules\beast_core\network\MACAddress.cpp">
<Filter>beast_core\network</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\network\NamedPipe.cpp">
<Filter>beast_core\network</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\network\Socket.cpp">
<Filter>beast_core\network</Filter>
</ClCompile>
@@ -1475,9 +1460,6 @@
<ClCompile Include="..\..\modules\beast_core\threads\HighResolutionTimer.cpp">
<Filter>beast_core\threads</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\threads\ReadWriteLock.cpp">
<Filter>beast_core\threads</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_core\time\PerformanceCounter.cpp">
<Filter>beast_core\time</Filter>
</ClCompile>
@@ -1910,6 +1892,18 @@
<ClCompile Include="..\..\beast\asio\abstract_socket.cpp">
<Filter>beast\asio</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\bind_handler_tests.cpp">
<Filter>beast\asio\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\shared_handler_tests.cpp">
<Filter>beast\asio\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\wrap_handler_tests.cpp">
<Filter>beast\asio\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\beast\asio\tests\enable_wait_for_async.test.cpp">
<Filter>beast\asio\tests</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\TODO.txt">

View File

@@ -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:

View File

@@ -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"

View File

@@ -1,95 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_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 <typename T = void>
class SafeBool : public detail::SafeBoolBase
{
public:
operator detail::SafeBoolBase::boolean_t () const
{
return (static_cast <T const*> (this))->asBoolean ()
? &SafeBoolBase::allowed : 0;
}
protected:
~SafeBool () { }
};
template <typename T, typename U>
void operator== (SafeBool <T> const& lhs, SafeBool <U> const& rhs)
{
lhs.disallowed ();
}
template <typename T, typename U>
void operator!= (SafeBool <T> const& lhs, SafeBool <U> const& rhs)
{
lhs.disallowed ();
}
}
#endif

View File

@@ -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"

View File

@@ -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!

14
beast/asio/README.md Normal file
View File

@@ -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.

View File

@@ -99,6 +99,21 @@ public:
{
return m_buffers.end ();
}
#if 0
template <class ConstBufferSequence>
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 <void*> (
*iter), boost::asio::buffer_size (*iter));
}
#endif
};
typedef buffer_sequence <boost::asio::const_buffer> const_buffers;

View File

@@ -0,0 +1,265 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_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 <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include "../cxx14/type_traits.h" // <type_traits>
namespace beast {
namespace asio {
namespace detail {
template <class Owner, class Handler>
class ref_counted_wrapped_handler
{
private:
static_assert (std::is_same <std::decay_t <Owner>, Owner>::value,
"Owner cannot be a const or reference type");
Handler m_handler;
std::reference_wrapper <Owner> 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 <class... Args>
void
operator() (Args&&... args)
{
m_handler (std::forward <Args> (args)...);
}
template <class... Args>
void
operator() (Args&&... args) const
{
m_handler (std::forward <Args> (args)...);
}
template <class Function>
friend
void
asio_handler_invoke (Function& f,
ref_counted_wrapped_handler* h)
{
boost_asio_handler_invoke_helpers::
invoke (f, h->m_handler);
}
template <class Function>
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 Derived>
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 <decltype(m_mutex)> lock (m_mutex);
++m_count;
}
void notify (std::true_type)
{
static_cast <Derived*> (this)->on_wait_for_async();
}
void notify (std::false_type)
{
}
void decrement()
{
std::lock_guard <decltype(m_mutex)> lock (m_mutex);
--m_count;
if (m_count == 0)
{
m_cond.notify_all();
notify (std::integral_constant <bool,
has_on_wait_for_async<Derived, void(void)>::value>());
}
}
template <class Owner, class Handler>
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 <decltype (m_mutex)> 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 <class Handler>
detail::ref_counted_wrapped_handler <
enable_wait_for_async,
std::remove_reference_t <Handler>
>
wrap_with_counter (Handler&& handler, bool continuation = false)
{
return detail::ref_counted_wrapped_handler <enable_wait_for_async,
std::remove_reference_t <Handler>> (*this,
std::forward <Handler> (handler), continuation);
}
template <class Handler>
detail::ref_counted_wrapped_handler <
enable_wait_for_async,
std::remove_reference_t <Handler>
>
wrap_with_counter (continuation_t, Handler&& handler)
{
return detail::ref_counted_wrapped_handler <enable_wait_for_async,
std::remove_reference_t <Handler>> (*this,
std::forward <Handler> (handler), true);
}
/** @} */
};
}
}
#endif

423
beast/asio/memory_buffer.h Normal file
View File

@@ -0,0 +1,423 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_ASIO_MEMORY_BUFFER_H_INCLUDED
#define BEAST_ASIO_MEMORY_BUFFER_H_INCLUDED
#include "../utility/empty_base_optimization.h"
#include <boost/asio/buffer.hpp>
#include <cstddef>
#include <type_traits>
namespace beast {
namespace asio {
template <
class T,
class Alloc = std::allocator <T>
>
class memory_buffer
: private empty_base_optimization <Alloc>
{
private:
static_assert (std::is_trivially_constructible <T>::value,
"T must be trivially constructible");
typedef empty_base_optimization <Alloc> Base;
using AllocTraits = std::allocator_traits <Alloc>;
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 <iterator> reverse_iterator;
typedef std::reverse_iterator <const_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 <class U, class A>
friend
void
swap (memory_buffer <U, A>& lhs,
memory_buffer <U, A>& rhs) noexcept;
};
//------------------------------------------------------------------------------
template <class T, class Alloc>
void
swap (memory_buffer <T, Alloc>& lhs,
memory_buffer <T, Alloc>& rhs) noexcept
{
std::swap (lhs.m_base, rhs.m_base);
std::swap (lhs.m_size, rhs.m_size);
}
template <class T, class A1, class A2>
inline
bool
operator== (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return std::equal (lhs.cbegin(), lhs.cend(),
rhs.cbegin(), rhs.cend());
}
template <class T, class A1, class A2>
inline
bool
operator!= (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return ! (lhs == rhs);
}
template <class T, class A1, class A2>
inline
bool
operator< (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return std::lexicographical_compare (
lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
}
template <class T, class A1, class A2>
inline
bool
operator>= (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return ! (lhs < rhs);
}
template <class T, class A1, class A2>
inline
bool
operator> (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return rhs < lhs;
}
template <class T, class A1, class A2>
inline
bool
operator<= (memory_buffer <T, A1> const& lhs,
memory_buffer <T, A2> const& rhs)
{
return ! (rhs < lhs);
}
}
}
#endif

View File

@@ -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 <functional>
@@ -260,9 +262,7 @@ public:
//------------------------------------------------------------------------------
/** Handler shared reference that provides io_service execution guarantees. */
template <
class Signature
>
template <class Signature>
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

View File

@@ -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 <has_get_io_service <this_layer_type,
boost::asio::io_service&()> > ());
#else
return get_io_service (std::true_type ());
#endif
}
boost::asio::io_service& get_io_service (

View File

@@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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.
*/
//==============================================================================
#include "BeastConfig.h"
#include "../../../modules/beast_core/beast_core.h" // for UnitTest
#include "../bind_handler.h"
#include "../enable_wait_for_async.h"
#include <boost/asio/io_service.hpp>
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 <owner>
{
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;
}

View File

@@ -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 <std::size_t Bytes>
class UnsignedInteger : public SafeBool <UnsignedInteger <Bytes> >
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 ();
}

View File

@@ -60,7 +60,7 @@ struct DoubleWidthUInt <std::uint32_t>
which return results by value cannot be included in the interface.
*/
template <typename UInt>
class UnsignedIntegerCalc : public SafeBool <UnsignedIntegerCalc <UInt> >
class UnsignedIntegerCalc
{
public:
typedef typename detail::DoubleWidthUInt <UInt>::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 ();
}

View File

@@ -20,6 +20,8 @@
#ifndef BEAST_MPL_ISCALLPOSSIBLE_H_INCLUDED
#define BEAST_MPL_ISCALLPOSSIBLE_H_INCLUDED
#include "../cxx14/type_traits.h" // <type_traits>
namespace beast {
namespace mpl {
@@ -160,10 +162,11 @@ struct trait_name##_detail
BEAST_DEFINE_HAS_MEMBER_FUNCTION(has_member, member_function_name); \
}; \
\
template <typename T, typename IsCallPossibleSignature> \
template <typename DT, typename IsCallPossibleSignature> \
struct trait_name \
{ \
private: \
typedef std::remove_reference_t <DT> 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 <typename Result> \
struct impl<true, Result(void)> \
{ \
static typename beast::mpl::is_call_possible_detail::add_reference<derived_type>::type test_me; \
\
static const bool value = \
sizeof( \
return_value_check<T, Result>::deduce( \
(test_me.member_function_name(), beast::mpl::is_call_possible_detail::void_exp_result<T>())) \
) == sizeof(yes); \
}; \
\
template <typename Result, typename Arg> \
struct impl<true, Result(Arg)> \
{ \

View File

@@ -1,106 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_NET_BASICS_BUFFERTYPE_H_INCLUDED
#define BEAST_NET_BASICS_BUFFERTYPE_H_INCLUDED
#include <type_traits>
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 <bool IsConst>
class BufferType
{
private:
typedef typename std::conditional <IsConst,
void const*, void*>::type pointer_type;
typedef typename std::conditional <IsConst,
uint8 const, uint8>::type byte_type;
public:
typedef std::size_t size_type;
BufferType ()
: m_data (nullptr)
, m_size (0)
{
}
template <bool OtherIsConst>
BufferType (BufferType <OtherIsConst> const& other)
: m_data (other.template cast <pointer_type> ())
, 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 <pointer_type> ();
m_size = other.size ();
return *this;
}
template <bool OtherIsConst>
BufferType& operator= (
BufferType <OtherIsConst> const& other) noexcept
{
m_data = other.template cast <pointer_type> ();
m_size = other.size ();
return *this;
}
template <typename T>
T cast () const noexcept
{
return static_cast <T> (m_data);
}
size_type size () const
{
return m_size;
}
BufferType operator+ (size_type n) const noexcept
{
return BufferType (cast <byte_type*> (),
size () - std::min (size(), n));
}
private:
pointer_type m_data;
std::size_t m_size;
};
/** @} */
}
#endif

View File

@@ -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 <Address, bool> from_string (std::string const& s);
static
std::pair <Address, bool>
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 <typename OutputStream>
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, bool>
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 <beast::IP::Address>
{
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);
}
};
}

View File

@@ -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, bool> 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

View File

@@ -1,50 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_THREADS_LOCKGUARD_H_INCLUDED
#define BEAST_THREADS_LOCKGUARD_H_INCLUDED
#include "../Uncopyable.h"
namespace beast {
template <typename Mutex>
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

View File

@@ -25,10 +25,11 @@
#define BEAST_THREADS_RECURSIVEMUTEX_H_INCLUDED
#include "../Config.h"
#include "LockGuard.h"
#include "UnlockGuard.h"
#include "TryLockGuard.h"
#include <mutex>
#if ! BEAST_WINDOWS
#include <pthread.h>
#endif
@@ -38,7 +39,7 @@ namespace beast {
class RecursiveMutex
{
public:
typedef LockGuard <RecursiveMutex> ScopedLockType;
typedef std::lock_guard <RecursiveMutex> ScopedLockType;
typedef UnlockGuard <RecursiveMutex> ScopedUnlockType;
typedef TryLockGuard <RecursiveMutex> ScopedTryLockType;

View File

@@ -30,19 +30,20 @@ template <typename ScopedType, typename Context, typename Handler>
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;
};
@@ -63,9 +64,11 @@ public:
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 <typename Arg>
explicit ScopedWrapperContext (Arg& arg)
: m_context (arg)
{ }
{
}
template <typename Handler>
detail::ScopedWrapper <ScopedType, Context, Handler> wrap (
@@ -85,7 +89,7 @@ public:
}
private:
Context m_context;
Context mutable m_context;
};
}

View File

@@ -20,9 +20,10 @@
#ifndef BEAST_THREADS_SHAREDMUTEXADAPTER_H_INCLUDED
#define BEAST_THREADS_SHAREDMUTEXADAPTER_H_INCLUDED
#include "LockGuard.h"
#include "SharedLockGuard.h"
#include <mutex>
namespace beast {
/** Adapts a regular Lockable to conform to the SharedMutex concept.
@@ -35,7 +36,7 @@ class SharedMutexAdapter
{
public:
typedef Mutex MutexType;
typedef LockGuard <SharedMutexAdapter> LockGuardType;
typedef std::lock_guard <SharedMutexAdapter> LockGuardType;
typedef SharedLockGuard <SharedMutexAdapter> SharedLockGuardType;
void lock() const

View File

@@ -25,9 +25,10 @@
#define BEAST_THREADS_SPINLOCK_H_INCLUDED
#include "../Atomic.h"
#include "LockGuard.h"
#include "UnlockGuard.h"
#include <mutex>
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 <SpinLock> ScopedLockType;
typedef std::lock_guard <SpinLock> ScopedLockType;
/** Provides the type of scoped unlocker to use with a SpinLock. */
typedef UnlockGuard <SpinLock> ScopedUnlockType;

View File

@@ -187,8 +187,8 @@ private:
Type object;
};
mutable Atomic<ObjectHolder*> first;
SpinLock lock;
Atomic<ObjectHolder*> mutable first;
SpinLock mutable lock;
#endif
};

View File

@@ -33,6 +33,10 @@ struct maybe_const
typename std::remove_const <T>::type>::type type;
};
/** Alias for omitting `typename`. */
template <bool IsConst, class T>
using maybe_const_t = typename maybe_const <IsConst,T>::type;
}
#endif

View File

@@ -22,7 +22,6 @@
#include "../Config.h"
#include "../SafeBool.h"
#include "../strings/String.h"
#include <stdexcept>
@@ -43,7 +42,6 @@ namespace beast {
*/
class Error
: public std::exception
, public SafeBool <Error>
{
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;

View File

@@ -20,8 +20,6 @@
#ifndef BEAST_UTILITY_JOURNAL_H_INCLUDED
#define BEAST_UTILITY_JOURNAL_H_INCLUDED
#include "../SafeBool.h"
#include <sstream>
namespace beast {
@@ -150,7 +148,7 @@ public:
//--------------------------------------------------------------------------
class Stream : public SafeBool <Stream>
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. */

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 <State>
struct State
{
enum State_t
{
@@ -54,7 +54,7 @@ struct State : SafeBool <State>
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;

View File

@@ -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

View File

@@ -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"

View File

@@ -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);
}

View File

@@ -266,16 +266,34 @@ 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 <class Condition>
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
Requirements:
Condition must be explicitly convertible to bool
*/
bool unexpected (bool falseCondition, String const& failureMessage = String::empty);
template <class Condition>
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.

View File

@@ -1,212 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <Pimpl>, 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 <char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
}
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
{
ScopedReadLock sl (lock);
return pimpl != nullptr ? pimpl->write (static_cast <const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
}

View File

@@ -883,226 +883,3 @@ void File::revealToUser() const
}
}
}
//==============================================================================
class NamedPipe::Pimpl : LeakChecked <NamedPipe::Pimpl>, 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;
}

View File

@@ -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 ();
}

View File

@@ -32,7 +32,7 @@ public:
/** A triplet identifying a mutex, a thread, and source code location.
*/
class Record : public SafeBool <Record>
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 <Agent>
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,

View File

@@ -1,153 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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();
}
}

View File

@@ -1,145 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 <ThreadRecursionCount> readerThreads;
};
#endif // BEAST_READWRITELOCK_H_INCLUDED

View File

@@ -1,82 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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

View File

@@ -1,82 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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