Automated merge with ssh://hg.lindenlab.com/viewer/viewer-2-0/
commit
ffad97ccb0
|
|
@ -276,6 +276,7 @@ LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}")
|
|||
LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
|
||||
|
|
|
|||
|
|
@ -45,10 +45,12 @@
|
|||
#include "llsingleton.h"
|
||||
#include "lldependencies.h"
|
||||
|
||||
/*==========================================================================*|
|
||||
// override this to allow binding free functions with more parameters
|
||||
#ifndef LLEVENTS_LISTENER_ARITY
|
||||
#define LLEVENTS_LISTENER_ARITY 10
|
||||
#endif
|
||||
|*==========================================================================*/
|
||||
|
||||
// hack for testing
|
||||
#ifndef testable
|
||||
|
|
|
|||
|
|
@ -38,22 +38,53 @@
|
|||
|
||||
#include "string_table.h"
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/iterator/indirect_iterator.hpp>
|
||||
|
||||
// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
// If KEY is not provided, then instances are stored in a simple set
|
||||
// *NOTE: see explicit specialization below for default KEY==T* case
|
||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
/// If KEY is not provided, then instances are stored in a simple set
|
||||
/// @NOTE: see explicit specialization below for default KEY==T* case
|
||||
template<typename T, typename KEY = T*>
|
||||
class LLInstanceTracker : boost::noncopyable
|
||||
{
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
||||
public:
|
||||
typedef typename std::map<KEY, T*>::iterator instance_iter;
|
||||
typedef typename std::map<KEY, T*>::const_iterator instance_const_iter;
|
||||
/// Dereferencing key_iter gives you a const KEY&
|
||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
||||
|
||||
static T* getInstance(const KEY& k) { instance_iter found = getMap().find(k); return (found == getMap().end()) ? NULL : found->second; }
|
||||
static T* getInstance(const KEY& k)
|
||||
{
|
||||
typename InstanceMap::const_iterator found = getMap().find(k);
|
||||
return (found == getMap().end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances() { return getMap().begin(); }
|
||||
static instance_iter endInstances() { return getMap().end(); }
|
||||
static key_iter beginKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap().begin(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
}
|
||||
static key_iter endKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap().end(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
}
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap().begin(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap().end(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static S32 instanceCount() { return getMap().size(); }
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add(key); }
|
||||
|
|
@ -69,11 +100,11 @@ private:
|
|||
}
|
||||
void remove() { getMap().erase(mKey); }
|
||||
|
||||
static std::map<KEY, T*>& getMap()
|
||||
static InstanceMap& getMap()
|
||||
{
|
||||
if (! sInstances)
|
||||
{
|
||||
sInstances = new std::map<KEY, T*>;
|
||||
sInstances = new InstanceMap;
|
||||
}
|
||||
return *sInstances;
|
||||
}
|
||||
|
|
@ -81,20 +112,27 @@ private:
|
|||
private:
|
||||
|
||||
KEY mKey;
|
||||
static std::map<KEY, T*>* sInstances;
|
||||
static InstanceMap* sInstances;
|
||||
};
|
||||
|
||||
// explicit specialization for default case where KEY is T*
|
||||
// use a simple std::set<T*>
|
||||
/// explicit specialization for default case where KEY is T*
|
||||
/// use a simple std::set<T*>
|
||||
template<typename T>
|
||||
class LLInstanceTracker<T, T*>
|
||||
{
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
public:
|
||||
typedef typename std::set<T*>::iterator instance_iter;
|
||||
typedef typename std::set<T*>::const_iterator instance_const_iter;
|
||||
/// Dereferencing key_iter gives you a T* (since T* is the key)
|
||||
typedef typename InstanceSet::iterator key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator<key_iter> instance_iter;
|
||||
|
||||
static instance_iter beginInstances() { return getSet().begin(); }
|
||||
static instance_iter endInstances() { return getSet().end(); }
|
||||
/// for completeness of analogy with the generic implementation
|
||||
static T* getInstance(T* k) { return k; }
|
||||
static key_iter beginKeys() { return getSet().begin(); }
|
||||
static key_iter endKeys() { return getSet().end(); }
|
||||
static instance_iter beginInstances() { return instance_iter(getSet().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet().end()); }
|
||||
static S32 instanceCount() { return getSet().size(); }
|
||||
|
||||
protected:
|
||||
|
|
@ -103,19 +141,19 @@ protected:
|
|||
|
||||
LLInstanceTracker(const LLInstanceTracker& other) { getSet().insert(static_cast<T*>(this)); }
|
||||
|
||||
static std::set<T*>& getSet() // called after getReady() but before go()
|
||||
static InstanceSet& getSet() // called after getReady() but before go()
|
||||
{
|
||||
if (! sInstances)
|
||||
{
|
||||
sInstances = new std::set<T*>;
|
||||
sInstances = new InstanceSet;
|
||||
}
|
||||
return *sInstances;
|
||||
}
|
||||
|
||||
static std::set<T*>* sInstances;
|
||||
static InstanceSet* sInstances;
|
||||
};
|
||||
|
||||
template <typename T, typename KEY> std::map<KEY, T*>* LLInstanceTracker<T, KEY>::sInstances = NULL;
|
||||
template <typename T> std::set<T*>* LLInstanceTracker<T, T*>::sInstances = NULL;
|
||||
template <typename T, typename KEY> typename LLInstanceTracker<T, KEY>::InstanceMap* LLInstanceTracker<T, KEY>::sInstances = NULL;
|
||||
template <typename T> typename LLInstanceTracker<T, T*>::InstanceSet* LLInstanceTracker<T, T*>::sInstances = NULL;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -583,13 +583,13 @@ void LLEventTimer::updateClass()
|
|||
std::list<LLEventTimer*> completed_timers;
|
||||
for (instance_iter iter = beginInstances(); iter != endInstances(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* @file llinstancetracker_test.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-11-10
|
||||
* @brief Test for llinstancetracker.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
||||
* Copyright (c) 2009, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llinstancetracker.h"
|
||||
// STL headers
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm> // std::sort()
|
||||
// std headers
|
||||
// external library headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
// other Linden headers
|
||||
#include "../test/lltut.h"
|
||||
|
||||
struct Keyed: public LLInstanceTracker<Keyed, std::string>
|
||||
{
|
||||
Keyed(const std::string& name):
|
||||
LLInstanceTracker<Keyed, std::string>(name),
|
||||
mName(name)
|
||||
{}
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
struct Unkeyed: public LLInstanceTracker<Unkeyed>
|
||||
{
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* TUT
|
||||
*****************************************************************************/
|
||||
namespace tut
|
||||
{
|
||||
struct llinstancetracker_data
|
||||
{
|
||||
};
|
||||
typedef test_group<llinstancetracker_data> llinstancetracker_group;
|
||||
typedef llinstancetracker_group::object object;
|
||||
llinstancetracker_group llinstancetrackergrp("llinstancetracker");
|
||||
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
ensure_equals(Keyed::instanceCount(), 0);
|
||||
{
|
||||
Keyed one("one");
|
||||
ensure_equals(Keyed::instanceCount(), 1);
|
||||
Keyed* found = Keyed::getInstance("one");
|
||||
ensure("couldn't find stack Keyed", found);
|
||||
ensure_equals("found wrong Keyed instance", found, &one);
|
||||
{
|
||||
boost::scoped_ptr<Keyed> two(new Keyed("two"));
|
||||
ensure_equals(Keyed::instanceCount(), 2);
|
||||
Keyed* found = Keyed::getInstance("two");
|
||||
ensure("couldn't find heap Keyed", found);
|
||||
ensure_equals("found wrong Keyed instance", found, two.get());
|
||||
}
|
||||
ensure_equals(Keyed::instanceCount(), 1);
|
||||
}
|
||||
Keyed* found = Keyed::getInstance("one");
|
||||
ensure("Keyed key lives too long", ! found);
|
||||
ensure_equals(Keyed::instanceCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<2>()
|
||||
{
|
||||
ensure_equals(Unkeyed::instanceCount(), 0);
|
||||
{
|
||||
Unkeyed one;
|
||||
ensure_equals(Unkeyed::instanceCount(), 1);
|
||||
Unkeyed* found = Unkeyed::getInstance(&one);
|
||||
ensure_equals(found, &one);
|
||||
{
|
||||
boost::scoped_ptr<Unkeyed> two(new Unkeyed);
|
||||
ensure_equals(Unkeyed::instanceCount(), 2);
|
||||
Unkeyed* found = Unkeyed::getInstance(two.get());
|
||||
ensure_equals(found, two.get());
|
||||
}
|
||||
ensure_equals(Unkeyed::instanceCount(), 1);
|
||||
}
|
||||
ensure_equals(Unkeyed::instanceCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<3>()
|
||||
{
|
||||
Keyed one("one"), two("two"), three("three");
|
||||
// We don't want to rely on the underlying container delivering keys
|
||||
// in any particular order. That allows us the flexibility to
|
||||
// reimplement LLInstanceTracker using, say, a hash map instead of a
|
||||
// std::map. We DO insist that every key appear exactly once.
|
||||
typedef std::vector<std::string> StringVector;
|
||||
StringVector keys(Keyed::beginKeys(), Keyed::endKeys());
|
||||
std::sort(keys.begin(), keys.end());
|
||||
StringVector::const_iterator ki(keys.begin());
|
||||
ensure_equals(*ki++, "one");
|
||||
ensure_equals(*ki++, "three");
|
||||
ensure_equals(*ki++, "two");
|
||||
// Use ensure() here because ensure_equals would want to display
|
||||
// mismatched values, and frankly that wouldn't help much.
|
||||
ensure("didn't reach end", ki == keys.end());
|
||||
|
||||
// Use a somewhat different approach to order independence with
|
||||
// beginInstances(): explicitly capture the instances we know in a
|
||||
// set, and delete them as we iterate through.
|
||||
typedef std::set<Keyed*> InstanceSet;
|
||||
InstanceSet instances;
|
||||
instances.insert(&one);
|
||||
instances.insert(&two);
|
||||
instances.insert(&three);
|
||||
for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances());
|
||||
ii != iend; ++ii)
|
||||
{
|
||||
Keyed& ref = *ii;
|
||||
ensure_equals("spurious instance", instances.erase(&ref), 1);
|
||||
}
|
||||
ensure_equals("unreported instance", instances.size(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<4>()
|
||||
{
|
||||
Unkeyed one, two, three;
|
||||
typedef std::set<Unkeyed*> KeySet;
|
||||
KeySet keys;
|
||||
keys.insert(&one);
|
||||
keys.insert(&two);
|
||||
keys.insert(&three);
|
||||
for (Unkeyed::key_iter ki(Unkeyed::beginKeys()), kend(Unkeyed::endKeys());
|
||||
ki != kend; ++ki)
|
||||
{
|
||||
ensure_equals("spurious key", keys.erase(*ki), 1);
|
||||
}
|
||||
ensure_equals("unreported key", keys.size(), 0);
|
||||
|
||||
KeySet instances;
|
||||
instances.insert(&one);
|
||||
instances.insert(&two);
|
||||
instances.insert(&three);
|
||||
for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances());
|
||||
ii != iend; ++ii)
|
||||
{
|
||||
Unkeyed& ref = *ii;
|
||||
ensure_equals("spurious instance", instances.erase(&ref), 1);
|
||||
}
|
||||
ensure_equals("unreported instance", instances.size(), 0);
|
||||
}
|
||||
} // namespace tut
|
||||
|
|
@ -792,8 +792,8 @@ void LLLayoutStack::calcMinExtents()
|
|||
//static
|
||||
void LLLayoutStack::updateClass()
|
||||
{
|
||||
for (LLInstanceTracker<LLLayoutStack>::instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
for (LLLayoutStack::instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
(*it)->updateLayout();
|
||||
it->updateLayout();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,8 +323,8 @@ void LLNameListCtrl::refreshAll(const LLUUID& id, const std::string& first,
|
|||
LLInstanceTracker<LLNameListCtrl>::instance_iter it;
|
||||
for (it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
LLNameListCtrl* ctrl = *it;
|
||||
ctrl->refresh(id, first, last, is_group);
|
||||
LLNameListCtrl& ctrl = *it;
|
||||
ctrl.refresh(id, first, last, is_group);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue