mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-26 02:18:04 +01:00
AsyncObserver (#4444)
* feat(AsyncObserver): Improve NotificationCenter speed and usability #4414 * fix(Notification): add missing header * feat(Any): add checkers for holding nullptr #4447 * feat(NotificationCenter): g++ build and refactoring #4414 * fix(Observer): compile errors on some compilers #4414 * fix(NotificationCenter): compile errors #4414 * chore(ParallelSocketAcceptor): remove unnecessary include and using from header * feat(AsyncNotificationCenter): add #4414 * test(AsyncNotificationCenter): add mixed observer types to the test #4414 * fix(AsyncNotificationCenter): hangs on program exit #4414 * fix(dev): friend not honored, temporarily make private members public * fix(AsyncNotificationCenter); remove default #4414
This commit is contained in:
committed by
GitHub
parent
30a0a06bac
commit
88be66972a
@@ -577,6 +577,7 @@
|
||||
<ClCompile Include="src\Ascii.cpp" />
|
||||
<ClCompile Include="src\ASCIIEncoding.cpp" />
|
||||
<ClCompile Include="src\AsyncChannel.cpp" />
|
||||
<ClCompile Include="src\AsyncNotificationCenter.cpp" />
|
||||
<ClCompile Include="src\AtomicCounter.cpp" />
|
||||
<ClCompile Include="src\Base32Decoder.cpp" />
|
||||
<ClCompile Include="src\Base32Encoder.cpp" />
|
||||
@@ -1493,6 +1494,7 @@
|
||||
<ClInclude Include="include\Poco\AccessExpireStrategy.h" />
|
||||
<ClInclude Include="include\Poco\ActiveDispatcher.h" />
|
||||
<ClInclude Include="include\Poco\ActiveMethod.h" />
|
||||
<ClInclude Include="include\Poco\AsyncObserver.h" />
|
||||
<ClInclude Include="include\Poco\ActiveResult.h" />
|
||||
<ClInclude Include="include\Poco\ActiveRunnable.h" />
|
||||
<ClInclude Include="include\Poco\ActiveStarter.h" />
|
||||
@@ -1502,6 +1504,8 @@
|
||||
<ClInclude Include="include\Poco\Ascii.h" />
|
||||
<ClInclude Include="include\Poco\ASCIIEncoding.h" />
|
||||
<ClInclude Include="include\Poco\AsyncChannel.h" />
|
||||
<ClInclude Include="include\Poco\AsyncObserver.h" />
|
||||
<ClInclude Include="include\Poco\AsyncNotificationCenter.h" />
|
||||
<ClInclude Include="include\Poco\AtomicCounter.h" />
|
||||
<ClInclude Include="include\Poco\AutoPtr.h" />
|
||||
<ClInclude Include="include\Poco\AutoReleasePool.h" />
|
||||
|
||||
@@ -573,6 +573,9 @@
|
||||
<ClCompile Include="src\AbstractObserver.cpp">
|
||||
<Filter>Notifications\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AsyncNotificationCenter.cpp">
|
||||
<Filter>Notifications\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Notification.cpp">
|
||||
<Filter>Notifications\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -1448,6 +1451,12 @@
|
||||
<ClInclude Include="include\Poco\NObserver.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Poco\AsyncObserver.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Poco\AsyncNotificationCenter.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Poco\Notification.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -878,6 +878,7 @@
|
||||
<ClCompile Include="src\Ascii.cpp" />
|
||||
<ClCompile Include="src\ASCIIEncoding.cpp" />
|
||||
<ClCompile Include="src\AsyncChannel.cpp" />
|
||||
<ClCompile Include="src\AsyncNotificationCenter.cpp" />
|
||||
<ClCompile Include="src\AtomicCounter.cpp" />
|
||||
<ClCompile Include="src\Base32Decoder.cpp" />
|
||||
<ClCompile Include="src\Base32Encoder.cpp" />
|
||||
@@ -2109,6 +2110,8 @@
|
||||
<ClInclude Include="include\Poco\Ascii.h" />
|
||||
<ClInclude Include="include\Poco\ASCIIEncoding.h" />
|
||||
<ClInclude Include="include\Poco\AsyncChannel.h" />
|
||||
<ClInclude Include="include\Poco\AsyncObserver.h" />
|
||||
<ClInclude Include="include\Poco\AsyncNotificationCenter.h" />
|
||||
<ClInclude Include="include\Poco\AtomicCounter.h" />
|
||||
<ClInclude Include="include\Poco\AutoPtr.h" />
|
||||
<ClInclude Include="include\Poco\AutoReleasePool.h" />
|
||||
|
||||
@@ -579,6 +579,9 @@
|
||||
<ClCompile Include="src\NotificationCenter.cpp">
|
||||
<Filter>Notifications\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\AsyncNotificationCenter.cpp">
|
||||
<Filter>Notifications\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\NotificationQueue.cpp">
|
||||
<Filter>Notifications\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -1447,6 +1450,12 @@
|
||||
<ClInclude Include="include\Poco\AbstractObserver.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Poco\AsyncObserver.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Poco\AsyncNotificationCenter.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Poco\NObserver.h">
|
||||
<Filter>Notifications\Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
include $(POCO_BASE)/build/rules/global
|
||||
|
||||
objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel ActiveThreadPool\
|
||||
objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel AsyncNotificationCenter ActiveThreadPool\
|
||||
Base32Decoder Base32Encoder Base64Decoder Base64Encoder \
|
||||
BinaryReader BinaryWriter Bugcheck ByteOrder Channel Checksum Clock Configurable ConsoleChannel \
|
||||
Condition CountingStream DateTime LocalDateTime DateTimeFormat DateTimeFormatter DateTimeParser \
|
||||
|
||||
@@ -37,12 +37,42 @@ public:
|
||||
AbstractObserver& operator = (const AbstractObserver& observer);
|
||||
|
||||
virtual void notify(Notification* pNf) const = 0;
|
||||
|
||||
virtual bool equals(const AbstractObserver& observer) const = 0;
|
||||
virtual bool accepts(Notification* pNf, const char* pName = 0) const = 0;
|
||||
|
||||
[[deprecated("use `Poco::Any accepts(Notification*)` instead")]]
|
||||
virtual bool accepts(Notification* pNf, const char* pName) const = 0;
|
||||
|
||||
virtual bool accepts(const Notification::Ptr& pNf) const = 0;
|
||||
|
||||
virtual AbstractObserver* clone() const = 0;
|
||||
|
||||
virtual void start();
|
||||
/// No-op.
|
||||
/// This method can be implemented by inheriting classes which require
|
||||
/// explicit start in order to begin processing notifications.
|
||||
|
||||
virtual void disable() = 0;
|
||||
|
||||
virtual int backlog() const;
|
||||
/// Returns number of queued messages that this Observer has.
|
||||
/// For non-active (synchronous) observers, always returns zero.
|
||||
};
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
||||
inline void AbstractObserver::start()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline int AbstractObserver::backlog() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
#define poco_any_assert(cond) do { if (!(cond)) std::abort(); } while (0)
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
class Any;
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace Dynamic {
|
||||
|
||||
class Var;
|
||||
@@ -409,12 +408,12 @@ ValueType* AnyCast(Any* operand)
|
||||
/// to the stored value.
|
||||
///
|
||||
/// Example Usage:
|
||||
/// MyType* pTmp = AnyCast<MyType*>(pAny).
|
||||
/// Will return NULL if the cast fails, i.e. types don't match.
|
||||
/// MyType* pTmp = AnyCast<MyType>(pAny).
|
||||
/// Returns nullptr if the types don't match.
|
||||
{
|
||||
return operand && operand->type() == typeid(ValueType)
|
||||
? &static_cast<Any::Holder<ValueType>*>(operand->content())->_held
|
||||
: 0;
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -424,8 +423,8 @@ const ValueType* AnyCast(const Any* operand)
|
||||
/// to the stored value.
|
||||
///
|
||||
/// Example Usage:
|
||||
/// const MyType* pTmp = AnyCast<MyType*>(pAny).
|
||||
/// Will return NULL if the cast fails, i.e. types don't match.
|
||||
/// const MyType* pTmp = AnyCast<MyType>(pAny).
|
||||
/// Returns nullptr if the types don't match.
|
||||
{
|
||||
return AnyCast<ValueType>(const_cast<Any*>(operand));
|
||||
}
|
||||
@@ -442,18 +441,19 @@ ValueType AnyCast(Any& operand)
|
||||
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
||||
/// these cases.
|
||||
{
|
||||
typedef typename TypeWrapper<ValueType>::TYPE NonRef;
|
||||
using NonRef = typename TypeWrapper<ValueType>::TYPE;
|
||||
|
||||
NonRef* result = AnyCast<NonRef>(&operand);
|
||||
if (!result)
|
||||
{
|
||||
std::string s = "RefAnyCast: Failed to convert between Any types ";
|
||||
std::string s(__func__);
|
||||
s.append(": Failed to convert between Any types "s);
|
||||
if (operand.content())
|
||||
{
|
||||
s.append(1, '(');
|
||||
s.append(operand.content()->type().name());
|
||||
s.append(Poco::demangle(operand.content()->type().name()));
|
||||
s.append(" => ");
|
||||
s.append(typeid(ValueType).name());
|
||||
s.append(Poco::demangle<ValueType>());
|
||||
s.append(1, ')');
|
||||
}
|
||||
throw BadCastException(s);
|
||||
@@ -473,7 +473,7 @@ ValueType AnyCast(const Any& operand)
|
||||
/// Some compilers will accept this code although a copy is returned. Use the RefAnyCast in
|
||||
/// these cases.
|
||||
{
|
||||
typedef typename TypeWrapper<ValueType>::TYPE NonRef;
|
||||
using NonRef = typename TypeWrapper<ValueType>::TYPE;
|
||||
|
||||
return AnyCast<NonRef&>(const_cast<Any&>(operand));
|
||||
}
|
||||
@@ -489,13 +489,14 @@ const ValueType& RefAnyCast(const Any & operand)
|
||||
ValueType* result = AnyCast<ValueType>(const_cast<Any*>(&operand));
|
||||
if (!result)
|
||||
{
|
||||
std::string s = "RefAnyCast: Failed to convert between Any types ";
|
||||
std::string s(__func__);
|
||||
s.append(": Failed to convert between Any types "s);
|
||||
if (operand.content())
|
||||
{
|
||||
s.append(1, '(');
|
||||
s.append(operand.content()->type().name());
|
||||
s.append(Poco::demangle(operand.content()->type().name()));
|
||||
s.append(" => ");
|
||||
s.append(typeid(ValueType).name());
|
||||
s.append(Poco::demangle<ValueType>());
|
||||
s.append(1, ')');
|
||||
}
|
||||
throw BadCastException(s);
|
||||
@@ -514,13 +515,14 @@ ValueType& RefAnyCast(Any& operand)
|
||||
ValueType* result = AnyCast<ValueType>(&operand);
|
||||
if (!result)
|
||||
{
|
||||
std::string s = "RefAnyCast: Failed to convert between Any types ";
|
||||
std::string s(__func__);
|
||||
s.append(": Failed to convert between Any types "s);
|
||||
if (operand.content())
|
||||
{
|
||||
s.append(1, '(');
|
||||
s.append(operand.content()->type().name());
|
||||
s.append(Poco::demangle(operand.content()->type().name()));
|
||||
s.append(" => ");
|
||||
s.append(typeid(ValueType).name());
|
||||
s.append(Poco::demangle<ValueType>());
|
||||
s.append(1, ')');
|
||||
}
|
||||
throw BadCastException(s);
|
||||
@@ -553,6 +555,26 @@ const ValueType* UnsafeAnyCast(const Any* operand)
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
bool AnyHoldsNullPtr(const Any& any)
|
||||
/// Returns true if any holds a null pointer.
|
||||
/// Fails to compile if `ValueType` is not a pointer.
|
||||
{
|
||||
poco_static_assert_ptr(ValueType);
|
||||
return (AnyCast<ValueType>(any) == nullptr);
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
bool AnyHoldsNullPtr(const Any* pAny)
|
||||
/// Returns true if the Any pointed to holds a null pointer.
|
||||
/// Returns false if `pAny` is a null pointer.
|
||||
{
|
||||
if (!pAny) return false;
|
||||
return (AnyHoldsNullPtr<ValueType>(*pAny));
|
||||
}
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
|
||||
77
Foundation/include/Poco/AsyncNotificationCenter.h
Normal file
77
Foundation/include/Poco/AsyncNotificationCenter.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// AsyncNotificationCenter.h
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Notifications
|
||||
// Module: AsyncNotificationCenter
|
||||
//
|
||||
// Definition of the AsyncNotificationCenter class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Foundation_AsyncNotificationCenter_INCLUDED
|
||||
#define Foundation_AsyncNotificationCenter_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Foundation.h"
|
||||
#include "Poco/NotificationCenter.h"
|
||||
#include "Poco/Thread.h"
|
||||
#include "Poco/Stopwatch.h"
|
||||
#include "Poco/Debugger.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/RunnableAdapter.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
class Foundation_API AsyncNotificationCenter: public NotificationCenter
|
||||
/// AsyncNotificationCenter decouples posting of notifications
|
||||
/// from notifying subscribers by calling observers' notification
|
||||
/// handler in a dedicated thread.
|
||||
{
|
||||
public:
|
||||
AsyncNotificationCenter();
|
||||
/// Creates the AsyncNotificationCenter and starts the notifying thread.
|
||||
|
||||
~AsyncNotificationCenter();
|
||||
/// Stops the notifying thread and destroys the AsyncNotificationCenter.
|
||||
|
||||
AsyncNotificationCenter& operator = (const AsyncNotificationCenter&) = delete;
|
||||
AsyncNotificationCenter(const AsyncNotificationCenter&) = delete;
|
||||
AsyncNotificationCenter& operator = (AsyncNotificationCenter&&) = delete;
|
||||
AsyncNotificationCenter(AsyncNotificationCenter&&) = delete;
|
||||
|
||||
virtual void postNotification(Notification::Ptr pNotification);
|
||||
/// Enqueues notification into the notification queue.
|
||||
|
||||
virtual int backlog() const;
|
||||
/// Returns the numbner of notifications in the notification queue.
|
||||
|
||||
private:
|
||||
void start();
|
||||
void stop();
|
||||
void dequeue();
|
||||
|
||||
using Adapter = RunnableAdapter<AsyncNotificationCenter>;
|
||||
|
||||
Thread _thread;
|
||||
NotificationQueue _nq;
|
||||
Adapter _ra;
|
||||
std::atomic<bool> _started;
|
||||
std::atomic<bool> _done;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif // Foundation_AsyncNotificationCenter_INCLUDED
|
||||
177
Foundation/include/Poco/AsyncObserver.h
Normal file
177
Foundation/include/Poco/AsyncObserver.h
Normal file
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// AsyncObserver.h
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Notifications
|
||||
// Module: AsyncObserver
|
||||
//
|
||||
// Definition of the AsyncObserver class template.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Foundation_AsyncObserver_INCLUDED
|
||||
#define Foundation_AsyncObserver_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Foundation.h"
|
||||
#include "Poco/NObserver.h"
|
||||
#include "Poco/Thread.h"
|
||||
#include "Poco/Stopwatch.h"
|
||||
#include "Poco/Debugger.h"
|
||||
#include "Poco/ErrorHandler.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/RunnableAdapter.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
template <class C, class N>
|
||||
class AsyncObserver: public NObserver<C, N>
|
||||
/// AsyncObserver notifies subscribers in a dedicated thread (as opposed
|
||||
/// to (N)Observer classes, which notify subscribers synchronously).
|
||||
/// In order to become active and process notifications, the start()
|
||||
/// method must be called.
|
||||
///
|
||||
/// This class is meant to be used with the NotificationCenter only.
|
||||
/// Notification processing thread can be started only once, and copying
|
||||
/// should be done before `start()` is called.
|
||||
{
|
||||
public:
|
||||
using Type = AsyncObserver<C, N>;
|
||||
using Matcher = typename NObserver<C, N>::Matcher;
|
||||
using Handler = typename NObserver<C, N>::Handler;
|
||||
using NotificationPtr = typename NObserver<C, N>::NotificationPtr;
|
||||
|
||||
AsyncObserver() = delete;
|
||||
|
||||
AsyncObserver(C& object, Handler handler, Matcher matcher = nullptr):
|
||||
NObserver<C, N>(object, handler, matcher),
|
||||
_ra(*this, &AsyncObserver::dequeue),
|
||||
_started(false),
|
||||
_done(false)
|
||||
{
|
||||
}
|
||||
|
||||
AsyncObserver(const AsyncObserver& observer):
|
||||
NObserver<C, N>(observer),
|
||||
_ra(*this, &AsyncObserver::dequeue),
|
||||
_started(false),
|
||||
_done(false)
|
||||
{
|
||||
poco_assert(observer._nq.size() == 0);
|
||||
}
|
||||
|
||||
~AsyncObserver()
|
||||
{
|
||||
disable();
|
||||
}
|
||||
|
||||
AsyncObserver& operator = (const AsyncObserver& observer)
|
||||
{
|
||||
if (&observer != this)
|
||||
{
|
||||
poco_assert(observer._nq.size() == 0);
|
||||
setObject(observer._pObject);
|
||||
setHandler(observer._handler);
|
||||
setMatcher(observer._matcher);
|
||||
_started = false;
|
||||
_done =false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual void notify(Notification* pNf) const
|
||||
{
|
||||
_nq.enqueueNotification(NotificationPtr(static_cast<N*>(pNf), true));
|
||||
}
|
||||
|
||||
virtual AbstractObserver* clone() const
|
||||
{
|
||||
return new AsyncObserver(*this);
|
||||
}
|
||||
|
||||
virtual void start()
|
||||
{
|
||||
Poco::ScopedLock l(this->mutex());
|
||||
if (_started)
|
||||
{
|
||||
throw Poco::InvalidAccessException(
|
||||
Poco::format("thread already started %s", poco_src_loc));
|
||||
}
|
||||
|
||||
_thread.start(_ra);
|
||||
Poco::Stopwatch sw;
|
||||
sw.start();
|
||||
while (!_started)
|
||||
{
|
||||
if (sw.elapsedSeconds() > 5)
|
||||
throw Poco::TimeoutException(poco_src_loc);
|
||||
Thread::sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void disable()
|
||||
{
|
||||
if (!_started.exchange(false)) return;
|
||||
_nq.wakeUpAll();
|
||||
while (!_done) Thread::sleep(100);
|
||||
_thread.join();
|
||||
NObserver<C, N>::disable();
|
||||
}
|
||||
|
||||
virtual int backlog() const
|
||||
{
|
||||
return _nq.size();
|
||||
}
|
||||
|
||||
private:
|
||||
void dequeue()
|
||||
{
|
||||
Notification::Ptr pNf;
|
||||
_started = true;
|
||||
_done = false;
|
||||
while ((pNf = _nq.waitDequeueNotification()))
|
||||
{
|
||||
try
|
||||
{
|
||||
this->handle(pNf.unsafeCast<N>());
|
||||
}
|
||||
catch (Poco::Exception& ex)
|
||||
{
|
||||
Poco::ErrorHandler::handle(ex);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
Poco::ErrorHandler::handle(ex);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Poco::ErrorHandler::handle();
|
||||
}
|
||||
}
|
||||
_done = true;
|
||||
_started = false;
|
||||
}
|
||||
|
||||
using Adapter = RunnableAdapter<AsyncObserver<C, N>>;
|
||||
|
||||
Thread _thread;
|
||||
mutable NotificationQueue _nq;
|
||||
Adapter _ra;
|
||||
std::atomic<bool> _started;
|
||||
std::atomic<bool> _done;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif // Foundation_AsyncObserver_INCLUDED
|
||||
@@ -165,42 +165,16 @@ protected:
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// poco_static_assert
|
||||
//
|
||||
// The following was ported from <boost/static_assert.hpp>
|
||||
//
|
||||
#define poco_static_assert(B) static_assert(B)
|
||||
|
||||
|
||||
template <bool x>
|
||||
struct POCO_STATIC_ASSERTION_FAILURE;
|
||||
|
||||
|
||||
template <>
|
||||
struct POCO_STATIC_ASSERTION_FAILURE<true>
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = 1
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <int x>
|
||||
struct poco_static_assert_test
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4))
|
||||
#define poco_static_assert(B) \
|
||||
typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \
|
||||
[POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>::value]
|
||||
#else
|
||||
#define poco_static_assert(B) \
|
||||
typedef poco_static_assert_test<sizeof(POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>)> \
|
||||
POCO_JOIN(poco_static_assert_typedef_, __LINE__) POCO_UNUSED
|
||||
#endif
|
||||
#define poco_static_assert_ptr(T) \
|
||||
static_assert(std::is_pointer_v<T> || \
|
||||
std::is_same_v<T, nullptr_t> || \
|
||||
std::is_member_pointer_v<T> || \
|
||||
std::is_member_function_pointer_v<T> || \
|
||||
std::is_member_object_pointer_v<T>, \
|
||||
"not a pointer")
|
||||
|
||||
|
||||
#endif // Foundation_Bugcheck_INCLUDED
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Notifications
|
||||
// Module: NotificationCenter
|
||||
// Module: NObserver
|
||||
//
|
||||
// Definition of the NObserver class template.
|
||||
//
|
||||
@@ -37,25 +37,39 @@ class NObserver: public AbstractObserver
|
||||
/// to use this template class.
|
||||
///
|
||||
/// This class template is quite similar to the Observer class
|
||||
/// template. The only difference is that the NObserver
|
||||
/// expects the callback function to accept a const AutoPtr&
|
||||
/// instead of a plain pointer as argument, thus simplifying memory
|
||||
/// management.
|
||||
/// template. The differences are:
|
||||
///
|
||||
/// - NObserver expects the callback function to accept a const AutoPtr&
|
||||
/// instead of a plain pointer as argument, thus simplifying memory
|
||||
/// management.
|
||||
///
|
||||
/// - In addition to dispatching notifications based on the Notification runtime
|
||||
/// type, NObserver can also notify subscribers based on the Notification name.
|
||||
/// To enable this functionality, a matcher function must be provided.
|
||||
/// Null matcher means no matching is performed and all notificiations
|
||||
/// of the type subscribed to are dispatched.
|
||||
{
|
||||
public:
|
||||
typedef AutoPtr<N> NotificationPtr;
|
||||
typedef void (C::*Callback)(const NotificationPtr&);
|
||||
using Type = NObserver<C, N>;
|
||||
using NotificationPtr = AutoPtr<N>;
|
||||
using Callback = void (C::*)(const NotificationPtr&);
|
||||
using Handler = Callback;
|
||||
using Matcher = bool (C::*)(const std::string&) const;
|
||||
|
||||
NObserver(C& object, Callback method):
|
||||
NObserver() = delete;
|
||||
|
||||
NObserver(C& object, Handler method, Matcher matcher = nullptr):
|
||||
_pObject(&object),
|
||||
_method(method)
|
||||
_handler(method),
|
||||
_matcher(matcher)
|
||||
{
|
||||
}
|
||||
|
||||
NObserver(const NObserver& observer):
|
||||
AbstractObserver(observer),
|
||||
_pObject(observer._pObject),
|
||||
_method(observer._method)
|
||||
_handler(observer._handler),
|
||||
_matcher(observer._matcher)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -68,54 +82,72 @@ public:
|
||||
if (&observer != this)
|
||||
{
|
||||
_pObject = observer._pObject;
|
||||
_method = observer._method;
|
||||
_handler = observer._handler;
|
||||
_matcher = observer._matcher;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void notify(Notification* pNf) const
|
||||
virtual void notify(Notification* pNf) const
|
||||
{
|
||||
Poco::Mutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (_pObject)
|
||||
{
|
||||
N* pCastNf = dynamic_cast<N*>(pNf);
|
||||
if (pCastNf)
|
||||
{
|
||||
NotificationPtr ptr(pCastNf, true);
|
||||
(_pObject->*_method)(ptr);
|
||||
}
|
||||
}
|
||||
handle(NotificationPtr(static_cast<N*>(pNf), true));
|
||||
}
|
||||
|
||||
bool equals(const AbstractObserver& abstractObserver) const
|
||||
virtual bool equals(const AbstractObserver& abstractObserver) const
|
||||
{
|
||||
const NObserver* pObs = dynamic_cast<const NObserver*>(&abstractObserver);
|
||||
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
|
||||
return pObs && pObs->_pObject == _pObject && pObs->_handler == _handler && pObs->_matcher == _matcher;
|
||||
}
|
||||
|
||||
bool accepts(Notification* pNf, const char* pName = 0) const
|
||||
[[deprecated("use `bool accepts(const Notification::Ptr&)` instead")]]
|
||||
virtual bool accepts(Notification* pNf, const char* pName) const
|
||||
{
|
||||
return dynamic_cast<N*>(pNf) && (!pName || pNf->name() == pName);
|
||||
return (!pName || pNf->name() == pName) && dynamic_cast<N*>(pNf) != nullptr;
|
||||
}
|
||||
|
||||
AbstractObserver* clone() const
|
||||
virtual bool accepts(const Notification::Ptr& pNf) const
|
||||
{
|
||||
return (match(pNf) && (pNf.template cast<N>() != nullptr));
|
||||
}
|
||||
|
||||
virtual AbstractObserver* clone() const
|
||||
{
|
||||
return new NObserver(*this);
|
||||
}
|
||||
|
||||
void disable()
|
||||
virtual void disable()
|
||||
{
|
||||
Poco::Mutex::ScopedLock lock(_mutex);
|
||||
|
||||
_pObject = 0;
|
||||
_pObject = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void handle(const NotificationPtr& ptr) const
|
||||
{
|
||||
Mutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (_pObject)
|
||||
(_pObject->*_handler)(ptr);
|
||||
}
|
||||
|
||||
bool match(const Notification::Ptr& ptr) const
|
||||
{
|
||||
Mutex::ScopedLock l(_mutex);
|
||||
|
||||
return _pObject && (!_matcher || (_pObject->*_matcher)(ptr->name()));
|
||||
}
|
||||
|
||||
Mutex& mutex() const
|
||||
{
|
||||
return _mutex;
|
||||
}
|
||||
|
||||
private:
|
||||
NObserver();
|
||||
|
||||
C* _pObject;
|
||||
Callback _method;
|
||||
Callback _handler;
|
||||
Matcher _matcher;
|
||||
mutable Poco::Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "Poco/Mutex.h"
|
||||
#include "Poco/RefCountedObject.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -37,7 +38,7 @@ class Foundation_API Notification: public RefCountedObject
|
||||
public:
|
||||
using Ptr = AutoPtr<Notification>;
|
||||
|
||||
Notification();
|
||||
Notification(const std::string& name = ""s);
|
||||
/// Creates the notification.
|
||||
|
||||
virtual std::string name() const;
|
||||
@@ -46,6 +47,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~Notification();
|
||||
std::unique_ptr<std::string> _pName;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -79,10 +79,11 @@ class Foundation_API NotificationCenter
|
||||
/// }
|
||||
{
|
||||
public:
|
||||
|
||||
NotificationCenter();
|
||||
/// Creates the NotificationCenter.
|
||||
|
||||
~NotificationCenter();
|
||||
virtual ~NotificationCenter();
|
||||
/// Destroys the NotificationCenter.
|
||||
|
||||
void addObserver(const AbstractObserver& observer);
|
||||
@@ -99,7 +100,7 @@ public:
|
||||
bool hasObserver(const AbstractObserver& observer) const;
|
||||
/// Returns true if the observer is registered with this NotificationCenter.
|
||||
|
||||
void postNotification(Notification::Ptr pNotification);
|
||||
virtual void postNotification(Notification::Ptr pNotification);
|
||||
/// Posts a notification to the NotificationCenter.
|
||||
/// The NotificationCenter then delivers the notification
|
||||
/// to all interested observers.
|
||||
@@ -120,13 +121,29 @@ public:
|
||||
std::size_t countObservers() const;
|
||||
/// Returns the number of registered observers.
|
||||
|
||||
virtual int backlog() const;
|
||||
/// Returns the sum of queued notifications
|
||||
/// for all observers (applies only to asynchronous observers,
|
||||
/// regular observers post notifications syncronously and
|
||||
/// never have a backlog).
|
||||
|
||||
static NotificationCenter& defaultCenter();
|
||||
/// Returns a reference to the default
|
||||
/// NotificationCenter.
|
||||
|
||||
protected:
|
||||
using AbstractObserverPtr = SharedPtr<AbstractObserver>;
|
||||
using ObserverList = std::vector<AbstractObserverPtr>;
|
||||
|
||||
Mutex& mutex()
|
||||
{
|
||||
return _mutex;
|
||||
}
|
||||
|
||||
ObserverList observersToNotify(const Notification::Ptr& pNotification) const;
|
||||
void notifyObservers(Notification::Ptr& pNotification);
|
||||
|
||||
private:
|
||||
typedef SharedPtr<AbstractObserver> AbstractObserverPtr;
|
||||
typedef std::vector<AbstractObserverPtr> ObserverList;
|
||||
|
||||
ObserverList _observers;
|
||||
mutable Mutex _mutex;
|
||||
|
||||
@@ -74,15 +74,10 @@ public:
|
||||
void notify(Notification* pNf) const
|
||||
{
|
||||
Poco::Mutex::ScopedLock lock(_mutex);
|
||||
|
||||
if (_pObject)
|
||||
{
|
||||
N* pCastNf = dynamic_cast<N*>(pNf);
|
||||
if (pCastNf)
|
||||
{
|
||||
pCastNf->duplicate();
|
||||
(_pObject->*_method)(pCastNf);
|
||||
}
|
||||
pNf->duplicate();
|
||||
(_pObject->*_method)(static_cast<N*>(pNf));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +87,15 @@ public:
|
||||
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
|
||||
}
|
||||
|
||||
bool accepts(Notification* pNf, const char* pName = 0) const
|
||||
[[deprecated("use `bool accepts(const Notification::Ptr&)` instead")]]
|
||||
bool accepts(Notification* pNf, const char* pName) const
|
||||
{
|
||||
return dynamic_cast<N*>(pNf) && (!pName || pNf->name() == pName);
|
||||
return (!pName || pNf->name() == pName) && (dynamic_cast<N*>(pNf) != nullptr);
|
||||
}
|
||||
|
||||
bool accepts(const Notification::Ptr& pNf) const
|
||||
{
|
||||
return (pNf.cast<N>() != nullptr);
|
||||
}
|
||||
|
||||
AbstractObserver* clone() const
|
||||
|
||||
@@ -32,7 +32,7 @@ class RunnableAdapter: public Runnable
|
||||
/// Usage:
|
||||
/// RunnableAdapter<MyClass> ra(myObject, &MyObject::doSomething));
|
||||
/// Thread thr;
|
||||
/// thr.Start(ra);
|
||||
/// thr.start(ra);
|
||||
///
|
||||
/// For using a freestanding or static member function as a thread
|
||||
/// target, please see the ThreadTarget class.
|
||||
|
||||
106
Foundation/src/AsyncNotificationCenter.cpp
Normal file
106
Foundation/src/AsyncNotificationCenter.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// AsyncNotificationCenter.cpp
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Notifications
|
||||
// Module: AsyncNotificationCenter
|
||||
//
|
||||
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/AsyncNotificationCenter.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
AsyncNotificationCenter::AsyncNotificationCenter(): _ra(*this, &AsyncNotificationCenter::dequeue),
|
||||
_started(false),
|
||||
_done(false)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
AsyncNotificationCenter::~AsyncNotificationCenter()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenter::postNotification(Notification::Ptr pNotification)
|
||||
{
|
||||
_nq.enqueueNotification(pNotification);
|
||||
}
|
||||
|
||||
|
||||
int AsyncNotificationCenter::backlog() const
|
||||
{
|
||||
return _nq.size();
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenter::start()
|
||||
{
|
||||
Poco::ScopedLock l(mutex());
|
||||
if (_started)
|
||||
{
|
||||
throw Poco::InvalidAccessException(
|
||||
Poco::format("thread already started %s", poco_src_loc));
|
||||
}
|
||||
_thread.start(_ra);
|
||||
Poco::Stopwatch sw;
|
||||
sw.start();
|
||||
while (!_started)
|
||||
{
|
||||
if (sw.elapsedSeconds() > 5)
|
||||
throw Poco::TimeoutException(poco_src_loc);
|
||||
Thread::sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenter::stop()
|
||||
{
|
||||
if (!_started.exchange(false)) return;
|
||||
_nq.wakeUpAll();
|
||||
while (!_done) Thread::sleep(100);
|
||||
_thread.join();
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenter::dequeue()
|
||||
{
|
||||
Notification::Ptr pNf;
|
||||
_started = true;
|
||||
_done = false;
|
||||
while ((pNf = _nq.waitDequeueNotification()))
|
||||
{
|
||||
try
|
||||
{
|
||||
notifyObservers(pNf);
|
||||
}
|
||||
catch (Poco::Exception& ex)
|
||||
{
|
||||
Poco::ErrorHandler::handle(ex);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
Poco::ErrorHandler::handle(ex);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Poco::ErrorHandler::handle();
|
||||
}
|
||||
}
|
||||
_done = true;
|
||||
_started = false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
@@ -19,7 +19,8 @@
|
||||
namespace Poco {
|
||||
|
||||
|
||||
Notification::Notification()
|
||||
Notification::Notification(const std::string& name):
|
||||
_pName(name.empty() ? nullptr : new std::string(name))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,7 +32,7 @@ Notification::~Notification()
|
||||
|
||||
std::string Notification::name() const
|
||||
{
|
||||
return typeid(*this).name();
|
||||
return _pName ? *_pName : typeid(*this).name();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ void NotificationCenter::addObserver(const AbstractObserver& observer)
|
||||
{
|
||||
Mutex::ScopedLock lock(_mutex);
|
||||
_observers.push_back(observer.clone());
|
||||
_observers.back()->start();
|
||||
}
|
||||
|
||||
|
||||
@@ -75,17 +76,34 @@ bool NotificationCenter::hasObserver(const AbstractObserver& observer) const
|
||||
}
|
||||
|
||||
|
||||
NotificationCenter::ObserverList NotificationCenter::observersToNotify(const Notification::Ptr& pNotification) const
|
||||
{
|
||||
ObserverList ret;
|
||||
ScopedLock<Mutex> lock(_mutex);
|
||||
for (auto& o : _observers)
|
||||
{
|
||||
if (o->accepts(pNotification))
|
||||
ret.push_back(o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenter::postNotification(Notification::Ptr pNotification)
|
||||
{
|
||||
poco_check_ptr (pNotification);
|
||||
|
||||
ScopedLockWithUnlock<Mutex> lock(_mutex);
|
||||
ObserverList observersToNotify(_observers);
|
||||
lock.unlock();
|
||||
for (auto& p: observersToNotify)
|
||||
{
|
||||
notifyObservers(pNotification);
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenter::notifyObservers(Notification::Ptr& pNotification)
|
||||
{
|
||||
poco_check_ptr (pNotification);
|
||||
|
||||
ObserverList observers = observersToNotify(pNotification);
|
||||
for (auto& p: observers)
|
||||
p->notify(pNotification);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +123,20 @@ std::size_t NotificationCenter::countObservers() const
|
||||
}
|
||||
|
||||
|
||||
int NotificationCenter::backlog() const
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
ScopedLockWithUnlock<Mutex> lock(_mutex);
|
||||
ObserverList observersToCount(_observers);
|
||||
lock.unlock();
|
||||
for (auto& p : observersToCount)
|
||||
cnt += p->backlog();
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
NotificationCenter& NotificationCenter::defaultCenter()
|
||||
{
|
||||
static NotificationCenter nc;
|
||||
|
||||
@@ -334,6 +334,111 @@ void AnyTest::testAnyInt()
|
||||
}
|
||||
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
void f() {}
|
||||
int m;
|
||||
};
|
||||
|
||||
|
||||
void AnyTest::testAnyPointer()
|
||||
{
|
||||
int i = 13;
|
||||
|
||||
Any a = &i;
|
||||
assertTrue (a.type() == typeid(int*));
|
||||
assertFalse (AnyHoldsNullPtr<int*>(a));
|
||||
assertFalse (AnyHoldsNullPtr<int*>(&a));
|
||||
int* p = AnyCast<int*>(&i);
|
||||
assertTrue (*p == 13);
|
||||
Any b = a;
|
||||
assertTrue (b.type() == typeid(int*));
|
||||
int* cpyI = AnyCast<int*>(b);
|
||||
assertTrue (*cpyI == *p);
|
||||
*cpyI = 20;
|
||||
assertTrue (*cpyI == *p);
|
||||
std::string* s = AnyCast<std::string>(&a);
|
||||
assertTrue (s == NULL);
|
||||
assertTrue (AnyCast<nullptr_t>(&a) == nullptr);
|
||||
|
||||
int* POCO_UNUSED tmp = AnyCast<int*>(a);
|
||||
const Any c = a;
|
||||
tmp = AnyCast<int*>(a);
|
||||
|
||||
Any nullPtr(nullptr);
|
||||
assertFalse (AnyHoldsNullPtr<nullptr_t>(nullptr));
|
||||
assertFalse (AnyHoldsNullPtr<void*>(0));
|
||||
assertTrue (AnyHoldsNullPtr<nullptr_t>(nullPtr));
|
||||
assertTrue (AnyHoldsNullPtr<nullptr_t>(&nullPtr));
|
||||
try
|
||||
{
|
||||
AnyHoldsNullPtr<void*>(nullPtr);
|
||||
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||
}
|
||||
catch(const Poco::BadCastException&) {}
|
||||
nullPtr = &i;
|
||||
try
|
||||
{
|
||||
assertFalse (AnyHoldsNullPtr<nullptr_t>(nullPtr));
|
||||
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||
}
|
||||
catch(const Poco::BadCastException&) {}
|
||||
assertFalse (AnyHoldsNullPtr<int*>(nullPtr));
|
||||
|
||||
void* voidPtr = nullptr;
|
||||
Any nullVoidPtr(voidPtr);
|
||||
assertTrue (AnyHoldsNullPtr<void*>(nullVoidPtr));
|
||||
try
|
||||
{
|
||||
AnyHoldsNullPtr<nullptr_t>(voidPtr);
|
||||
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||
}
|
||||
catch(const Poco::BadCastException&) {}
|
||||
|
||||
using FP = void (AnyTest::*)();
|
||||
FP fp = nullptr;
|
||||
Any funcPtr(fp);
|
||||
assertTrue (AnyHoldsNullPtr<FP>(funcPtr));
|
||||
try
|
||||
{
|
||||
AnyHoldsNullPtr<FP>(voidPtr);
|
||||
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||
}
|
||||
catch(const Poco::BadCastException&) {}
|
||||
funcPtr = &AnyTest::testAnyPointer;
|
||||
assertFalse (AnyHoldsNullPtr<FP>(funcPtr));
|
||||
|
||||
using OP = decltype(&AnyTest::_dummyObject);
|
||||
OP op = nullptr;
|
||||
Any objPtr(op);
|
||||
assertTrue (AnyHoldsNullPtr<OP>(objPtr));
|
||||
objPtr = &AnyTest::_dummyObject;
|
||||
try
|
||||
{
|
||||
AnyHoldsNullPtr<OP>(funcPtr);
|
||||
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||
}
|
||||
catch(const Poco::BadCastException&) {}
|
||||
|
||||
assertFalse (AnyHoldsNullPtr<OP>(objPtr));
|
||||
|
||||
using MP = decltype(&AnyTest::_dummy);
|
||||
MP mp = nullptr;
|
||||
Any memPtr(mp);
|
||||
assertTrue (AnyHoldsNullPtr<MP>(memPtr));
|
||||
memPtr = &AnyTest::_dummy;
|
||||
try
|
||||
{
|
||||
AnyHoldsNullPtr<MP>(objPtr);
|
||||
fail ("AnyCast must fail", __LINE__, __FILE__);
|
||||
}
|
||||
catch(const Poco::BadCastException&) {}
|
||||
|
||||
assertFalse (AnyHoldsNullPtr<MP>(memPtr));
|
||||
}
|
||||
|
||||
|
||||
void AnyTest::testAnyComplexType()
|
||||
{
|
||||
SomeClass str(13,std::string("hello"));
|
||||
@@ -456,6 +561,7 @@ CppUnit::Test* AnyTest::suite()
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnySwap);
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnyEmptyCopy);
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnyCastToReference);
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnyPointer);
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnyInt);
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnyComplexType);
|
||||
CppUnit_addTest(pSuite, AnyTest, testAnyVector);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
class AnyTest: public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
class Dummy{};
|
||||
|
||||
AnyTest(const std::string& name);
|
||||
~AnyTest();
|
||||
|
||||
@@ -33,6 +35,7 @@ public:
|
||||
void testAnyEmptyCopy();
|
||||
void testAnyCastToReference();
|
||||
|
||||
void testAnyPointer();
|
||||
void testAnyInt();
|
||||
void testAnyComplexType();
|
||||
void testAnyVector();
|
||||
@@ -42,6 +45,10 @@ public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
private:
|
||||
int _dummy = 0;
|
||||
Dummy _dummyObject;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ void FIFOEventTest::testAsyncNotifyBenchmark()
|
||||
assertTrue (vresult[i].data() == (i*2));
|
||||
}
|
||||
sw.stop();
|
||||
times.push_back(sw.elapsed()/1000);
|
||||
times.push_back(static_cast<int>(sw.elapsed()/1000));
|
||||
vresult.clear();
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ void FIFOEventTest::onAsyncBench(const void* pSender, int& i)
|
||||
|
||||
int FIFOEventTest::getCount() const
|
||||
{
|
||||
return _count;
|
||||
return static_cast<int>(_count.load());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,24 +12,40 @@
|
||||
#include "CppUnit/TestCaller.h"
|
||||
#include "CppUnit/TestSuite.h"
|
||||
#include "Poco/NotificationCenter.h"
|
||||
#include "Poco/AsyncNotificationCenter.h"
|
||||
#include "Poco/Observer.h"
|
||||
#include "Poco/NObserver.h"
|
||||
#include "Poco/AsyncObserver.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
|
||||
|
||||
using Poco::NotificationCenter;
|
||||
using Poco::AsyncNotificationCenter;
|
||||
using Poco::Observer;
|
||||
using Poco::NObserver;
|
||||
using Poco::AsyncObserver;
|
||||
using Poco::Notification;
|
||||
using Poco::AutoPtr;
|
||||
|
||||
|
||||
class TestNotification: public Notification
|
||||
{
|
||||
public:
|
||||
TestNotification()
|
||||
{}
|
||||
|
||||
TestNotification(const std::string& name):
|
||||
Notification(name)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
NotificationCenterTest::NotificationCenterTest(const std::string& name): CppUnit::TestCase(name)
|
||||
NotificationCenterTest::NotificationCenterTest(const std::string& name):
|
||||
CppUnit::TestCase(name),
|
||||
_handle1Done(false),
|
||||
_handleAuto1Done(false),
|
||||
_handleAsync1Done(false),
|
||||
_handleAsync2Done(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -39,14 +55,14 @@ NotificationCenterTest::~NotificationCenterTest()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::test1()
|
||||
void NotificationCenterTest::testNotificationCenter1()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::test2()
|
||||
void NotificationCenterTest::testNotificationCenter2()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
Observer<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
||||
@@ -64,7 +80,7 @@ void NotificationCenterTest::test2()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::test3()
|
||||
void NotificationCenterTest::testNotificationCenter3()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||
@@ -88,7 +104,7 @@ void NotificationCenterTest::test3()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::test4()
|
||||
void NotificationCenterTest::testNotificationCenter4()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||
@@ -119,7 +135,7 @@ void NotificationCenterTest::test4()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::test5()
|
||||
void NotificationCenterTest::testNotificationCenter5()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
@@ -137,7 +153,7 @@ void NotificationCenterTest::test5()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAuto()
|
||||
void NotificationCenterTest::testNotificationCenterAuto()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||
@@ -148,7 +164,59 @@ void NotificationCenterTest::testAuto()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testDefaultCenter()
|
||||
void NotificationCenterTest::testAsyncObserver()
|
||||
{
|
||||
using ObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
NotificationCenter nc;
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenter()
|
||||
{
|
||||
using ObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc;
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testDefaultNotificationCenter()
|
||||
{
|
||||
NotificationCenter& nc = NotificationCenter::defaultCenter();
|
||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
@@ -159,11 +227,38 @@ void NotificationCenterTest::testDefaultCenter()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testMixedObservers()
|
||||
{
|
||||
using AObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc;
|
||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||
nc.addObserver(AObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.postNotification(new Notification);
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
|
||||
while (!_handle1Done || !_handleAuto1Done || !_handleAsync1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(AObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue (_set.size() == 3);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
assertTrue (_set.find("handleAuto") != _set.end());
|
||||
assertTrue (_set.find("handleAsync1") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handle1(Poco::Notification* pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
poco_check_ptr (pNf);
|
||||
AutoPtr<Notification> nf = pNf;
|
||||
_set.insert("handle1");
|
||||
_handle1Done = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +288,31 @@ void NotificationCenterTest::handleTest(TestNotification* pNf)
|
||||
|
||||
void NotificationCenterTest::handleAuto(const AutoPtr<Notification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAuto");
|
||||
_handleAuto1Done = true;
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handleAsync1(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAsync1");
|
||||
_handleAsync1Done = true;
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handleAsync2(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAsync2");
|
||||
_handleAsync2Done = true;
|
||||
}
|
||||
|
||||
|
||||
bool NotificationCenterTest::matchAsync(const std::string& name) const
|
||||
{
|
||||
return name.find("asyncNotification") == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,13 +331,16 @@ CppUnit::Test* NotificationCenterTest::suite()
|
||||
{
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NotificationCenterTest");
|
||||
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, test1);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, test2);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, test3);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, test4);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, test5);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAuto);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testDefaultCenter);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter1);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter2);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter3);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter4);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter5);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenterAuto);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncObserver);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenter);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testDefaultNotificationCenter);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testMixedObservers);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "CppUnit/TestCase.h"
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Mutex.h"
|
||||
#include <set>
|
||||
|
||||
|
||||
@@ -30,13 +31,16 @@ public:
|
||||
NotificationCenterTest(const std::string& name);
|
||||
~NotificationCenterTest();
|
||||
|
||||
void test1();
|
||||
void test2();
|
||||
void test3();
|
||||
void test4();
|
||||
void test5();
|
||||
void testAuto();
|
||||
void testDefaultCenter();
|
||||
void testNotificationCenter1();
|
||||
void testNotificationCenter2();
|
||||
void testNotificationCenter3();
|
||||
void testNotificationCenter4();
|
||||
void testNotificationCenter5();
|
||||
void testNotificationCenterAuto();
|
||||
void testAsyncObserver();
|
||||
void testAsyncNotificationCenter();
|
||||
void testDefaultNotificationCenter();
|
||||
void testMixedObservers();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
@@ -49,9 +53,17 @@ protected:
|
||||
void handle3(Poco::Notification* pNf);
|
||||
void handleTest(TestNotification* pNf);
|
||||
void handleAuto(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handleAsync1(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
void handleAsync2(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
bool matchAsync(const std::string& name) const;
|
||||
|
||||
private:
|
||||
std::set<std::string> _set;
|
||||
std::atomic<bool> _handle1Done;
|
||||
std::atomic<bool> _handleAuto1Done;
|
||||
std::atomic<bool> _handleAsync1Done;
|
||||
std::atomic<bool> _handleAsync2Done;
|
||||
Poco::Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1997,12 +1997,12 @@ void VarTest::testLimitsFloat()
|
||||
{
|
||||
if (std::numeric_limits<double>::max() != std::numeric_limits<float>::max())
|
||||
{
|
||||
double iMin = -1 * std::numeric_limits<float>::max();
|
||||
constexpr double iMin = -1 * std::numeric_limits<float>::max();
|
||||
Var da = iMin * 10;
|
||||
try { float POCO_UNUSED f; f = da; fail("must throw", __LINE__, __FILE__); }
|
||||
catch (RangeException&) {}
|
||||
|
||||
double iMax = std::numeric_limits<float>::max();
|
||||
constexpr double iMax = std::numeric_limits<float>::max();
|
||||
da = iMax * 10;
|
||||
try { float POCO_UNUSED f; f = da; fail("must throw", __LINE__, __FILE__); }
|
||||
catch (RangeException&) {}
|
||||
@@ -2027,13 +2027,13 @@ void VarTest::testLimitsFloat()
|
||||
float f = 0.f;
|
||||
try { f = anyInt.convert<float>(); fail("must throw", __LINE__, __FILE__); }
|
||||
catch (Poco::RangeException&) {}
|
||||
i = f;
|
||||
i = static_cast<int64_t>(f);
|
||||
assertTrue (0 == i);
|
||||
|
||||
double d = 0.;
|
||||
try { d = anyInt.convert<double>(); fail("must throw", __LINE__, __FILE__); }
|
||||
catch (Poco::RangeException&) {}
|
||||
i = d;
|
||||
i = static_cast<int64_t>(d);
|
||||
assertTrue (0 == i);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user