Skip to content
Snippets Groups Projects
Commit 2fa60679 authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files
parents 98ca90be 68ec7da9
No related branches found
No related tags found
No related merge requests found
......@@ -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>
// 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
#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
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;
static T* getInstance(const KEY& k) { instance_iter found = getMap().find(k); return (found == getMap().end()) ? NULL : found->second; }
/// 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)
{
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 @@ class LLInstanceTracker : boost::noncopyable
}
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 @@ class LLInstanceTracker : boost::noncopyable
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;
static instance_iter beginInstances() { return getSet().begin(); }
static instance_iter endInstances() { return getSet().end(); }
/// 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;
/// 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 @@ class LLInstanceTracker<T, T*>
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 );
}
}
}
......
/**
* @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);
}
}
......
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