Automated merge with ssh://hg.lindenlab.com/viewer/viewer-2-0/

meow-7.2.2
Nat Goodspeed 2009-11-10 19:22:52 -05:00
commit ffad97ccb0
7 changed files with 234 additions and 33 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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