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

@@ -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: \
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;
};
@@ -55,17 +56,19 @@ template <typename Context, typename ScopedType>
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 <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;