diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 42 | ||||
| -rw-r--r-- | indra/llcommon/lleventapi.cpp | 30 | ||||
| -rw-r--r-- | indra/llcommon/lleventapi.h | 53 | ||||
| -rw-r--r-- | indra/llcommon/lleventdispatcher.cpp | 12 | ||||
| -rw-r--r-- | indra/llcommon/lleventdispatcher.h | 35 | ||||
| -rw-r--r-- | indra/llcommon/llevents.h | 2 | ||||
| -rw-r--r-- | indra/llcommon/llinstancetracker.h | 112 | ||||
| -rw-r--r-- | indra/llcommon/llprocesslauncher.h | 8 | ||||
| -rw-r--r-- | indra/llcommon/llqueuedthread.cpp | 7 | ||||
| -rw-r--r-- | indra/llcommon/lltimer.cpp | 12 | ||||
| -rw-r--r-- | indra/llcommon/llversionserver.h | 2 | ||||
| -rw-r--r-- | indra/llcommon/llversionviewer.h | 2 | ||||
| -rw-r--r-- | indra/llcommon/tests/llinstancetracker_test.cpp | 160 | 
13 files changed, 383 insertions, 94 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index f785698612..e41c75846b 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -1,3 +1,4 @@ +  # -*- cmake -*-  project(llcommon) @@ -6,11 +7,9 @@ include(00-Common)  include(LLCommon)  include(Linking)  include(Boost) -include (Pth) - -if (WINDOWS) -    include(CopyWinLibs) -endif (WINDOWS) +include(Pth) +include(LLSharedLibs) +include(Copy3rdPartyLibs)  include_directories(      ${EXPAT_INCLUDE_DIRS} @@ -42,6 +41,7 @@ set(llcommon_SOURCE_FILES      llerror.cpp      llerrorthread.cpp      llevent.cpp +    lleventapi.cpp      lleventcoro.cpp      lleventdispatcher.cpp      lleventfilter.cpp @@ -141,6 +141,7 @@ set(llcommon_HEADER_FILES      llerrorlegacy.h      llerrorthread.h      llevent.h +    lleventapi.h      lleventcoro.h      lleventdispatcher.h      lleventfilter.h @@ -243,35 +244,7 @@ list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})  if(LLCOMMON_LINK_SHARED)      add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) - -    if(SHARED_LIB_STAGING_DIR) -        # *FIX:Mani --- -        # llcommon.dll get written to the DLL staging directory. -        # Also this directory is shared with RunBuildTest.cmake, y'know, for the tests. -        set_target_properties(llcommon PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR}) -        if(NOT WINDOWS) -          get_target_property(LLCOMMON_PATH llcommon LOCATION) -          get_filename_component(LLCOMMON_FILE ${LLCOMMON_PATH} NAME) -          add_custom_command( -            TARGET llcommon POST_BUILD -            COMMAND ${CMAKE_COMMAND} -            ARGS -              -E -              copy_if_different -              ${LLCOMMON_PATH} -              ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/${LLCOMMON_FILE} -            COMMENT "Copying llcommon to the staging folder." -            ) -        endif(NOT WINDOWS) -    endif(SHARED_LIB_STAGING_DIR) - -    if (DARWIN) -      set_target_properties(llcommon PROPERTIES -        BUILD_WITH_INSTALL_RPATH 1 -        INSTALL_NAME_DIR "@executable_path/../Resources" -        ) -    endif(DARWIN) - +	ll_stage_sharedlib(llcommon)  else(LLCOMMON_LINK_SHARED)      add_library (llcommon ${llcommon_SOURCE_FILES})  endif(LLCOMMON_LINK_SHARED) @@ -305,6 +278,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}") diff --git a/indra/llcommon/lleventapi.cpp b/indra/llcommon/lleventapi.cpp new file mode 100644 index 0000000000..1dd104da8f --- /dev/null +++ b/indra/llcommon/lleventapi.cpp @@ -0,0 +1,30 @@ +/** + * @file   lleventapi.cpp + * @author Nat Goodspeed + * @date   2009-11-10 + * @brief  Implementation for lleventapi. + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "lleventapi.h" +// STL headers +// std headers +// external library headers +// other Linden headers + +LLEventAPI::LLEventAPI(const std::string& name, const std::string& desc, const std::string& field): +    lbase(name, field), +    ibase(name), +    mDesc(desc) +{ +} + +LLEventAPI::~LLEventAPI() +{ +} diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h new file mode 100644 index 0000000000..2cd3b5bf89 --- /dev/null +++ b/indra/llcommon/lleventapi.h @@ -0,0 +1,53 @@ +/** + * @file   lleventapi.h + * @author Nat Goodspeed + * @date   2009-10-28 + * @brief  LLEventAPI is the base class for every class that wraps a C++ API + *         in an event API + * (see https://wiki.lindenlab.com/wiki/Incremental_Viewer_Automation/Event_API). + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLEVENTAPI_H) +#define LL_LLEVENTAPI_H + +#include "lleventdispatcher.h" +#include "llinstancetracker.h" +#include <string> + +/** + * LLEventAPI not only provides operation dispatch functionality, inherited + * from LLDispatchListener -- it also gives us event API introspection. + * Deriving from LLInstanceTracker lets us enumerate instances. + */ +class LL_COMMON_API LLEventAPI: public LLDispatchListener, +                  public LLInstanceTracker<LLEventAPI, std::string> +{ +    typedef LLDispatchListener lbase; +    typedef LLInstanceTracker<LLEventAPI, std::string> ibase; + +public: +    /** +     * @param name LLEventPump name on which this LLEventAPI will listen. This +     * also serves as the LLInstanceTracker instance key. +     * @param desc Documentation string shown to a client trying to discover +     * available event APIs. +     * @param field LLSD::Map key used by LLDispatchListener to look up the +     * subclass method to invoke [default "op"]. +     */ +    LLEventAPI(const std::string& name, const std::string& desc, const std::string& field="op"); +    virtual ~LLEventAPI(); + +    /// Get the string name of this LLEventAPI +    std::string getName() const { return ibase::getKey(); } +    /// Get the documentation string +    std::string getDesc() const { return mDesc; } + +private: +    std::string mDesc; +}; + +#endif /* ! defined(LL_LLEVENTAPI_H) */ diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp index 6b1413d054..017bf3a521 100644 --- a/indra/llcommon/lleventdispatcher.cpp +++ b/indra/llcommon/lleventdispatcher.cpp @@ -36,9 +36,11 @@ LLEventDispatcher::~LLEventDispatcher()  }  /// Register a callable by name -void LLEventDispatcher::add(const std::string& name, const Callable& callable, const LLSD& required) +void LLEventDispatcher::add(const std::string& name, const std::string& desc, +                            const Callable& callable, const LLSD& required)  { -    mDispatch[name] = DispatchMap::mapped_type(callable, required); +    mDispatch.insert(DispatchMap::value_type(name, +                                             DispatchMap::mapped_type(callable, desc, required)));  }  void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const @@ -98,14 +100,14 @@ bool LLEventDispatcher::attemptCall(const std::string& name, const LLSD& event)      }      // Found the name, so it's plausible to even attempt the call. But first,      // validate the syntax of the event itself. -    std::string mismatch(llsd_matches(found->second.second, event)); +    std::string mismatch(llsd_matches(found->second.mRequired, event));      if (! mismatch.empty())      {          LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ") calling '" << name                                       << "': bad request: " << mismatch << LL_ENDL;      }      // Event syntax looks good, go for it! -    (found->second.first)(event); +    (found->second.mFunc)(event);      return true;                    // tell caller we were able to call  } @@ -116,7 +118,7 @@ LLEventDispatcher::Callable LLEventDispatcher::get(const std::string& name) cons      {          return Callable();      } -    return found->second.first; +    return found->second.mFunc;  }  LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key): diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index 5a86b90bff..eba7b607f1 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -44,7 +44,10 @@ public:       * is used to validate the structure of each incoming event (see       * llsd_matches()).       */ -    void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD()); +    void add(const std::string& name, +             const std::string& desc, +             const Callable& callable, +             const LLSD& required=LLSD());      /**       * Special case: a subclass of this class can pass an unbound member @@ -52,18 +55,22 @@ public:       * <tt>boost::bind()</tt> expression.       */      template <class CLASS> -    void add(const std::string& name, void (CLASS::*method)(const LLSD&), +    void add(const std::string& name, +             const std::string& desc, +             void (CLASS::*method)(const LLSD&),               const LLSD& required=LLSD())      { -        addMethod<CLASS>(name, method, required); +        addMethod<CLASS>(name, desc, method, required);      }      /// Overload for both const and non-const methods      template <class CLASS> -    void add(const std::string& name, void (CLASS::*method)(const LLSD&) const, +    void add(const std::string& name, +             const std::string& desc, +             void (CLASS::*method)(const LLSD&) const,               const LLSD& required=LLSD())      { -        addMethod<CLASS>(name, method, required); +        addMethod<CLASS>(name, desc, method, required);      }      /// Unregister a callable @@ -86,7 +93,8 @@ public:  private:      template <class CLASS, typename METHOD> -    void addMethod(const std::string& name, const METHOD& method, const LLSD& required) +    void addMethod(const std::string& name, const std::string& desc, +                   const METHOD& method, const LLSD& required)      {          CLASS* downcast = dynamic_cast<CLASS*>(this);          if (! downcast) @@ -95,7 +103,7 @@ private:          }          else          { -            add(name, boost::bind(method, downcast, _1), required); +            add(name, desc, boost::bind(method, downcast, _1), required);          }      }      void addFail(const std::string& name, const std::string& classname) const; @@ -103,7 +111,18 @@ private:      bool attemptCall(const std::string& name, const LLSD& event) const;      std::string mDesc, mKey; -    typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap; +    struct DispatchEntry +    { +        DispatchEntry(const Callable& func, const std::string& desc, const LLSD& required): +            mFunc(func), +            mDesc(desc), +            mRequired(required) +        {} +        Callable mFunc; +        std::string mDesc; +        LLSD mRequired; +    }; +    typedef std::map<std::string, DispatchEntry> DispatchMap;      DispatchMap mDispatch;  }; diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 192d79b27d..f52cf33fd8 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -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 diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index ea50acbbc5..11fe523651 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -38,42 +38,73 @@  #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 S32 instanceCount() { return getMap().size(); } +	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); } -	virtual ~LLInstanceTracker() { remove(); } -	virtual void setKey(KEY key) { remove(); add(key); } +	LLInstanceTracker(KEY key) { add_(key); } +	virtual ~LLInstanceTracker() { remove_(); } +	virtual void setKey(KEY key) { remove_(); add_(key); }  	virtual const KEY& getKey() const { return mKey; }  private: -	void add(KEY key)  +	void add_(KEY key)   	{   		mKey = key;  -		getMap()[key] = static_cast<T*>(this);  +		getMap_()[key] = static_cast<T*>(this);   	} -	void remove() { getMap().erase(mKey); } +	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,41 +112,48 @@ 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; - -	static instance_iter beginInstances() { return getSet().begin(); } -	static instance_iter endInstances() { return getSet().end(); } -	static S32 instanceCount() { return getSet().size(); } +	/// 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: -	LLInstanceTracker() { getSet().insert(static_cast<T*>(this)); } -	virtual ~LLInstanceTracker() { getSet().erase(static_cast<T*>(this)); } +	LLInstanceTracker() { getSet_().insert(static_cast<T*>(this)); } +	virtual ~LLInstanceTracker() { getSet_().erase(static_cast<T*>(this)); } -	LLInstanceTracker(const LLInstanceTracker& other) { getSet().insert(static_cast<T*>(this)); } +	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 diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h index 880562157f..929d547f6e 100644 --- a/indra/llcommon/llprocesslauncher.h +++ b/indra/llcommon/llprocesslauncher.h @@ -70,6 +70,14 @@ public:  	// This needs to be called periodically on Mac/Linux to clean up zombie processes.  	static void reap(void); +	 +	// Accessors for platform-specific process ID +#if LL_WINDOWS +	HANDLE getProcessHandle() { return mProcessHandle; }; +#else +	pid_t getProcessID() { return mProcessID; }; +#endif	 +	  private:  	std::string mExecutable;  	std::string mWorkingDir; diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 395d298887..e7ad571a90 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -113,8 +113,11 @@ S32 LLQueuedThread::update(U32 max_time_ms)  {  	if (!mStarted)  	{ -		startThread(); -		mStarted = TRUE; +		if (!mThreaded) +		{ +			startThread(); +			mStarted = TRUE; +		}  	}  	return updateQueue(max_time_ms);  } diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index ea5b0c03ef..ef3e8dbc94 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -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 );  			}  		}  	} diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index 71c6fc0591..0f1e59a18c 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -36,7 +36,7 @@  const S32 LL_VERSION_MAJOR = 1;  const S32 LL_VERSION_MINOR = 31;  const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 3256; +const S32 LL_VERSION_BUILD = 200030;  const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 082d054ba2..540aea4252 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -36,7 +36,7 @@  const S32 LL_VERSION_MAJOR = 2;  const S32 LL_VERSION_MINOR = 0;  const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 3256; +const S32 LL_VERSION_BUILD = 200030;  const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp new file mode 100644 index 0000000000..7415f2d33b --- /dev/null +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -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  | 
