Skip to content
Snippets Groups Projects
Commit 18e2b9ca authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

DRTVWR-476: Remove llwrap(), LLListenerWrapper[Base] and support.

The only usage of any of this was in test code.
parent 0cde6669
No related branches found
No related tags found
No related merge requests found
# -*- cmake -*-
project(llcommon)
......@@ -185,7 +184,6 @@ set(llcommon_HEADER_FILES
llkeythrottle.h
llleap.h
llleaplistener.h
lllistenerwrapper.h
llliveappconfig.h
lllivefile.h
llmainthreadtask.h
......
......@@ -814,62 +814,6 @@ class LL_COMMON_API LLReqID
LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,
const std::string& replyKey="reply");
/**
* Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We
* provide virtual @c accept_xxx() methods, customization points allowing a
* subclass access to certain data visible at LLEventPump::listen() time.
* Example subclass usage:
*
* @code
* myEventPump.listen("somename",
* llwrap<MyListenerWrapper>(boost::bind(&MyClass::method, instance, _1)));
* @endcode
*
* Because of the anticipated usage (note the anonymous temporary
* MyListenerWrapper instance in the example above), the @c accept_xxx()
* methods must be @c const.
*/
class LL_COMMON_API LLListenerWrapperBase
{
public:
/// New instance. The accept_xxx() machinery makes it important to use
/// shared_ptrs for our data. Many copies of this object are made before
/// the instance that actually ends up in the signal, yet accept_xxx()
/// will later be called on the @em original instance. All copies of the
/// same original instance must share the same data.
LLListenerWrapperBase():
mName(new std::string),
mConnection(new LLBoundListener)
{
}
/// Copy constructor. Copy shared_ptrs to original instance data.
LLListenerWrapperBase(const LLListenerWrapperBase& that):
mName(that.mName),
mConnection(that.mConnection)
{
}
virtual ~LLListenerWrapperBase() {}
/// Ask LLEventPump::listen() for the listener name
virtual void accept_name(const std::string& name) const
{
*mName = name;
}
/// Ask LLEventPump::listen() for the new connection
virtual void accept_connection(const LLBoundListener& connection) const
{
*mConnection = connection;
}
protected:
/// Listener name.
boost::shared_ptr<std::string> mName;
/// Connection.
boost::shared_ptr<LLBoundListener> mConnection;
};
/*****************************************************************************
* Underpinnings
*****************************************************************************/
......@@ -1121,19 +1065,7 @@ namespace LLEventDetail
// Boost.Signals, in case we were passed a boost::ref().
visit_each(visitor, LLEventDetail::unwrap(raw_listener));
// Make the connection using passed function.
LLBoundListener connection(connect_func(listener));
// If the LISTENER is an LLListenerWrapperBase subclass, pass it the
// desired information. It's important that we pass the raw_listener
// so the compiler can make decisions based on its original type.
const LLListenerWrapperBase* lwb =
ll_template_cast<const LLListenerWrapperBase*>(&raw_listener);
if (lwb)
{
lwb->accept_name(name);
lwb->accept_connection(connection);
}
// In any case, show new connection to caller.
return connection;
return connect_func(listener);
}
} // namespace LLEventDetail
......
/**
* @file lllistenerwrapper.h
* @author Nat Goodspeed
* @date 2009-11-30
* @brief Introduce LLListenerWrapper template
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if ! defined(LL_LLLISTENERWRAPPER_H)
#define LL_LLLISTENERWRAPPER_H
#include "llevents.h" // LLListenerWrapperBase
#include <boost/visit_each.hpp>
/**
* Template base class for coding wrappers for LLEventPump listeners.
*
* Derive your listener wrapper from LLListenerWrapper. You must use
* LLLISTENER_WRAPPER_SUBCLASS() so your subclass will play nicely with
* boost::visit_each (q.v.). That way boost::signals2 can still detect
* derivation from LLEventTrackable, and so forth.
*/
template <typename LISTENER>
class LLListenerWrapper: public LLListenerWrapperBase
{
public:
/// Wrap an arbitrary listener object
LLListenerWrapper(const LISTENER& listener):
mListener(listener)
{}
/// call
virtual bool operator()(const LLSD& event)
{
return mListener(event);
}
/// Allow boost::visit_each() to peek at our mListener.
template <class V>
void accept_visitor(V& visitor) const
{
using boost::visit_each;
visit_each(visitor, mListener, 0);
}
private:
LISTENER mListener;
};
/**
* Specialize boost::visit_each() (leveraging ADL) to peek inside an
* LLListenerWrapper<T> to traverse its LISTENER. We borrow the
* accept_visitor() pattern from boost::bind(), avoiding the need to make
* mListener public.
*/
template <class V, typename T>
void visit_each(V& visitor, const LLListenerWrapper<T>& wrapper, int)
{
wrapper.accept_visitor(visitor);
}
/// use this (sigh!) for each subclass of LLListenerWrapper<T> you write
#define LLLISTENER_WRAPPER_SUBCLASS(CLASS) \
template <class V, typename T> \
void visit_each(V& visitor, const CLASS<T>& wrapper, int) \
{ \
visit_each(visitor, static_cast<const LLListenerWrapper<T>&>(wrapper), 0); \
} \
\
/* Have to state this explicitly, rather than using LL_TEMPLATE_CONVERTIBLE, */ \
/* because the source type is itself a template. */ \
template <typename T> \
struct ll_template_cast_impl<const LLListenerWrapperBase*, const CLASS<T>*> \
{ \
const LLListenerWrapperBase* operator()(const CLASS<T>* wrapper) \
{ \
return wrapper; \
} \
}
/**
* Make an instance of a listener wrapper. Every wrapper class must be a
* template accepting a listener object of arbitrary type. In particular, the
* type of a boost::bind() expression is deliberately undocumented. So we
* can't just write Wrapper<CorrectType>(boost::bind(...)). Instead we must
* write llwrap<Wrapper>(boost::bind(...)).
*/
template <template<typename> class WRAPPER, typename T>
WRAPPER<T> llwrap(const T& listener)
{
return WRAPPER<T>(listener);
}
/**
* This LLListenerWrapper template subclass is used to report entry/exit to an
* event listener, by changing this:
* @code
* someEventPump.listen("MyClass",
* boost::bind(&MyClass::method, ptr, _1));
* @endcode
* to this:
* @code
* someEventPump.listen("MyClass",
* llwrap<LLCoutListener>(
* boost::bind(&MyClass::method, ptr, _1)));
* @endcode
*/
template <class LISTENER>
class LLCoutListener: public LLListenerWrapper<LISTENER>
{
typedef LLListenerWrapper<LISTENER> super;
public:
/// Wrap an arbitrary listener object
LLCoutListener(const LISTENER& listener):
super(listener)
{}
/// call
virtual bool operator()(const LLSD& event)
{
std::cout << "Entering listener " << *super::mName << " with " << event << std::endl;
bool handled = super::operator()(event);
std::cout << "Leaving listener " << *super::mName;
if (handled)
{
std::cout << " (handled)";
}
std::cout << std::endl;
return handled;
}
};
LLLISTENER_WRAPPER_SUBCLASS(LLCoutListener);
/**
* This LLListenerWrapper template subclass is used to log entry/exit to an
* event listener, by changing this:
* @code
* someEventPump.listen("MyClass",
* boost::bind(&MyClass::method, ptr, _1));
* @endcode
* to this:
* @code
* someEventPump.listen("MyClass",
* llwrap<LLLogListener>(
* boost::bind(&MyClass::method, ptr, _1)));
* @endcode
*/
template <class LISTENER>
class LLLogListener: public LLListenerWrapper<LISTENER>
{
typedef LLListenerWrapper<LISTENER> super;
public:
/// Wrap an arbitrary listener object
LLLogListener(const LISTENER& listener):
super(listener)
{}
/// call
virtual bool operator()(const LLSD& event)
{
LL_DEBUGS("LLLogListener") << "Entering listener " << *super::mName << " with " << event << LL_ENDL;
bool handled = super::operator()(event);
LL_DEBUGS("LLLogListener") << "Leaving listener " << *super::mName;
if (handled)
{
LL_CONT << " (handled)";
}
LL_CONT << LL_ENDL;
return handled;
}
};
LLLISTENER_WRAPPER_SUBCLASS(LLLogListener);
#endif /* ! defined(LL_LLLISTENERWRAPPER_H) */
......@@ -38,7 +38,6 @@
#define testable public
#include "llevents.h"
#undef testable
#include "lllistenerwrapper.h"
// STL headers
// std headers
#include <iostream>
......@@ -633,33 +632,6 @@ ensure("implicit disconnect", ! connection.connected());
heaptest.post(2);
}
template<> template<>
void events_object::test<15>()
{
// This test ensures that using an LLListenerWrapper subclass doesn't
// block Boost.Signals2 from recognizing a bound LLEventTrackable
// subclass.
set_test_name("listen(llwrap<LLLogListener>(boost::bind(...TempTrackableListener ref...)))");
bool live = false;
LLEventPump& heaptest(pumps.obtain("heaptest"));
LLBoundListener connection;
{
TempTrackableListener tempListener("temp", live);
ensure("TempTrackableListener constructed", live);
connection = heaptest.listen(tempListener.getName(),
llwrap<LLLogListener>(
boost::bind(&TempTrackableListener::call,
boost::ref(tempListener), _1)));
heaptest.post(1);
check_listener("received", tempListener, 1);
} // presumably this will make tempListener go away?
// verify that
ensure("TempTrackableListener destroyed", ! live);
ensure("implicit disconnect", ! connection.connected());
// now just make sure we don't blow up trying to access a freed object!
heaptest.post(2);
}
class TempSharedListener: public TempListener,
public boost::enable_shared_from_this<TempSharedListener>
{
......@@ -670,7 +642,7 @@ TempSharedListener(const std::string& name, bool& liveFlag):
};
template<> template<>
void events_object::test<16>()
void events_object::test<15>()
{
set_test_name("listen(boost::bind(...TempSharedListener ref...))");
#if 0
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment