summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt1
-rw-r--r--indra/llcommon/indra_constants.h1
-rw-r--r--indra/llcommon/llhandle.h217
-rw-r--r--indra/llcommon/llinitparam.h16
-rw-r--r--indra/llcommon/llregistry.h30
-rw-r--r--indra/llcommon/llstl.h51
-rw-r--r--indra/llcommon/lltypeinfolookup.h141
-rw-r--r--indra/llcommon/llversionviewer.h2
8 files changed, 357 insertions, 102 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index dd7b8c6eb8..36a8319189 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -174,6 +174,7 @@ set(llcommon_HEADER_FILES
llfoldertype.h
llformat.h
llframetimer.h
+ llhandle.h
llhash.h
llheartbeat.h
llhttpstatuscodes.h
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 0745696ef3..0da83720bd 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -62,6 +62,7 @@ enum LAND_STAT_FLAGS
STAT_FILTER_BY_PARCEL = 0x00000001,
STAT_FILTER_BY_OWNER = 0x00000002,
STAT_FILTER_BY_OBJECT = 0x00000004,
+ STAT_FILTER_BY_PARCEL_NAME = 0x00000008,
STAT_REQUEST_LAST_ENTRY = 0x80000000,
};
diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h
new file mode 100644
index 0000000000..6af5e198d6
--- /dev/null
+++ b/indra/llcommon/llhandle.h
@@ -0,0 +1,217 @@
+/**
+* @file llhandle.h
+* @brief "Handle" to an object (usually a floater) whose lifetime you don't
+* control.
+*
+* $LicenseInfo:firstyear=2001&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$
+*/
+#ifndef LLHANDLE_H
+#define LLHANDLE_H
+
+#include "llpointer.h"
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/utility/enable_if.hpp>
+
+/**
+ * Helper object for LLHandle. Don't instantiate these directly, used
+ * exclusively by LLHandle.
+ */
+class LLTombStone : public LLRefCount
+{
+public:
+ LLTombStone(void* target = NULL) : mTarget(target) {}
+
+ void setTarget(void* target) { mTarget = target; }
+ void* getTarget() const { return mTarget; }
+private:
+ mutable void* mTarget;
+};
+
+/**
+ * LLHandles are used to refer to objects whose lifetime you do not control or influence.
+ * Calling get() on a handle will return a pointer to the referenced object or NULL,
+ * if the object no longer exists. Note that during the lifetime of the returned pointer,
+ * you are assuming that the object will not be deleted by any action you perform,
+ * or any other thread, as normal when using pointers, so avoid using that pointer outside of
+ * the local code block.
+ *
+ * https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669
+ *
+ * The implementation is like some "weak pointer" implementations. When we
+ * can't control the lifespan of the referenced object of interest, we can
+ * still instantiate a proxy object whose lifespan we DO control, and store in
+ * the proxy object a dumb pointer to the actual target. Then we just have to
+ * ensure that on destruction of the target object, the proxy's dumb pointer
+ * is set NULL.
+ *
+ * LLTombStone is our proxy object. LLHandle contains an LLPointer to the
+ * LLTombStone, so every copy of an LLHandle increments the LLTombStone's ref
+ * count as usual.
+ *
+ * One copy of the LLHandle, specifically the LLRootHandle, must be stored in
+ * the referenced object. Destroying the LLRootHandle is what NULLs the
+ * proxy's target pointer.
+ *
+ * Minor optimization: we want LLHandle's mTombStone to always be a valid
+ * LLPointer, saving some conditionals in dereferencing. That's the
+ * getDefaultTombStone() mechanism. The default LLTombStone object's target
+ * pointer is always NULL, so it's semantically identical to allowing
+ * mTombStone to be invalid.
+ */
+template <typename T>
+class LLHandle
+{
+ template <typename U> friend class LLHandle;
+ template <typename U> friend class LLHandleProvider;
+public:
+ LLHandle() : mTombStone(getDefaultTombStone()) {}
+
+ template<typename U>
+ LLHandle(const LLHandle<U>& other, typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0)
+ : mTombStone(other.mTombStone)
+ {}
+
+ bool isDead() const
+ {
+ return mTombStone->getTarget() == NULL;
+ }
+
+ void markDead()
+ {
+ mTombStone = getDefaultTombStone();
+ }
+
+ T* get() const
+ {
+ return reinterpret_cast<T*>(mTombStone->getTarget());
+ }
+
+ friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
+ {
+ return lhs.mTombStone == rhs.mTombStone;
+ }
+ friend bool operator!= (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
+ {
+ return !(lhs == rhs);
+ }
+ friend bool operator< (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
+ {
+ return lhs.mTombStone < rhs.mTombStone;
+ }
+ friend bool operator> (const LLHandle<T>& lhs, const LLHandle<T>& rhs)
+ {
+ return lhs.mTombStone > rhs.mTombStone;
+ }
+
+protected:
+ LLPointer<LLTombStone> mTombStone;
+
+private:
+ typedef T* pointer_t;
+ static LLPointer<LLTombStone>& getDefaultTombStone()
+ {
+ static LLPointer<LLTombStone> sDefaultTombStone = new LLTombStone;
+ return sDefaultTombStone;
+ }
+};
+
+/**
+ * LLRootHandle isa LLHandle which must be stored in the referenced object.
+ * You can either store it directly and explicitly bind(this), or derive from
+ * LLHandleProvider (q.v.) which automates that for you. The essential point
+ * is that destroying the LLRootHandle (as a consequence of destroying the
+ * referenced object) calls unbind(), setting the LLTombStone's target pointer
+ * NULL.
+ */
+template <typename T>
+class LLRootHandle : public LLHandle<T>
+{
+public:
+ typedef LLRootHandle<T> self_t;
+ typedef LLHandle<T> base_t;
+
+ LLRootHandle(T* object) { bind(object); }
+ LLRootHandle() {};
+ ~LLRootHandle() { unbind(); }
+
+ // this is redundant, since an LLRootHandle *is* an LLHandle
+ //LLHandle<T> getHandle() { return LLHandle<T>(*this); }
+
+ void bind(T* object)
+ {
+ // unbind existing tombstone
+ if (LLHandle<T>::mTombStone.notNull())
+ {
+ if (LLHandle<T>::mTombStone->getTarget() == (void*)object) return;
+ LLHandle<T>::mTombStone->setTarget(NULL);
+ }
+ // tombstone reference counted, so no paired delete
+ LLHandle<T>::mTombStone = new LLTombStone((void*)object);
+ }
+
+ void unbind()
+ {
+ LLHandle<T>::mTombStone->setTarget(NULL);
+ }
+
+ //don't allow copying of root handles, since there should only be one
+private:
+ LLRootHandle(const LLRootHandle& other) {};
+};
+
+/**
+ * Use this as a mixin for simple classes that need handles and when you don't
+ * want handles at multiple points of the inheritance hierarchy
+ */
+template <typename T>
+class LLHandleProvider
+{
+public:
+ LLHandle<T> getHandle() const
+ {
+ // perform lazy binding to avoid small tombstone allocations for handle
+ // providers whose handles are never referenced
+ mHandle.bind(static_cast<T*>(const_cast<LLHandleProvider<T>* >(this)));
+ return mHandle;
+ }
+
+protected:
+ typedef LLHandle<T> handle_type_t;
+ LLHandleProvider()
+ {
+ // provided here to enforce T deriving from LLHandleProvider<T>
+ }
+
+ template <typename U>
+ LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const
+ {
+ LLHandle<U> downcast_handle;
+ downcast_handle.mTombStone = getHandle().mTombStone;
+ return downcast_handle;
+ }
+
+
+private:
+ mutable LLRootHandle<T> mHandle;
+};
+
+#endif
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index 99983a19cb..9a6d1eff5c 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -35,7 +35,7 @@
#include <boost/shared_ptr.hpp>
#include "llerror.h"
-#include "lltypeinfolookup.h"
+#include "llstl.h"
namespace LLInitParam
{
@@ -212,14 +212,6 @@ namespace LLInitParam
public:
- struct CompareTypeID
- {
- bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
- {
- return lhs->before(*rhs);
- }
- };
-
typedef std::vector<std::pair<std::string, bool> > name_stack_t;
typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t;
typedef std::vector<std::string> possible_values_t;
@@ -228,9 +220,9 @@ namespace LLInitParam
typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);
typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t;
- typedef LLTypeInfoLookup<parser_read_func_t> parser_read_func_map_t;
- typedef LLTypeInfoLookup<parser_write_func_t> parser_write_func_map_t;
- typedef LLTypeInfoLookup<parser_inspect_func_t> parser_inspect_func_map_t;
+ typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t;
+ typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t;
+ typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t;
Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
: mParseSilently(false),
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index 36d7f7a44c..853c427a13 100644
--- a/indra/llcommon/llregistry.h
+++ b/indra/llcommon/llregistry.h
@@ -31,30 +31,16 @@
#include <boost/type_traits.hpp>
#include "llsingleton.h"
-#include "lltypeinfolookup.h"
+#include "llstl.h"
template <typename T>
-class LLRegistryDefaultComparator
+struct LLRegistryDefaultComparator
{
- bool operator()(const T& lhs, const T& rhs) { return lhs < rhs; }
-};
-
-template <typename KEY, typename VALUE>
-struct LLRegistryMapSelector
-{
- typedef std::map<KEY, VALUE> type;
-};
-
-template <typename VALUE>
-struct LLRegistryMapSelector<std::type_info*, VALUE>
-{
- typedef LLTypeInfoLookup<VALUE> type;
-};
-
-template <typename VALUE>
-struct LLRegistryMapSelector<const std::type_info*, VALUE>
-{
- typedef LLTypeInfoLookup<VALUE> type;
+ bool operator()(const T& lhs, const T& rhs) const
+ {
+ using std::less;
+ return less<T>()(lhs, rhs);
+ }
};
template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
@@ -72,7 +58,7 @@ public:
{
friend class LLRegistry<KEY, VALUE, COMPARATOR>;
public:
- typedef typename LLRegistryMapSelector<KEY, VALUE>::type registry_map_t;
+ typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;
bool add(ref_const_key_t key, ref_const_value_t value)
{
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 8ad12c9a03..d3941e1bc9 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -33,6 +33,7 @@
#include <vector>
#include <set>
#include <deque>
+#include <typeinfo>
// Use to compare the first element only of a pair
// e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;
@@ -470,4 +471,54 @@ llbind2nd(const _Operation& __oper, const _Tp& __x)
return llbinder2nd<_Operation>(__oper, _Arg2_type(__x));
}
+/**
+ * Compare std::type_info* pointers a la std::less. We break this out as a
+ * separate function for use in two different std::less specializations.
+ */
+inline
+bool before(const std::type_info* lhs, const std::type_info* rhs)
+{
+#if LL_LINUX && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
+ // If we're building on Linux with gcc, and it's either gcc 3.x or
+ // 4.{0,1,2,3}, then we have to use a workaround. Note that we use gcc on
+ // Mac too, and some people build with gcc on Windows (cygwin or mingw).
+ // On Linux, different load modules may produce different type_info*
+ // pointers for the same type. Have to compare name strings to get good
+ // results.
+ return strcmp(lhs->name(), rhs->name()) < 0;
+#else // not Linux, or gcc 4.4+
+ // Just use before(), as we normally would
+ return lhs->before(*rhs);
+#endif
+}
+
+/**
+ * Specialize std::less<std::type_info*> to use std::type_info::before().
+ * See MAINT-1175. It is NEVER a good idea to directly compare std::type_info*
+ * because, on Linux, you might get different std::type_info* pointers for the
+ * same type (from different load modules)!
+ */
+namespace std
+{
+ template <>
+ struct less<const std::type_info*>:
+ public std::binary_function<const std::type_info*, const std::type_info*, bool>
+ {
+ bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
+ {
+ return before(lhs, rhs);
+ }
+ };
+
+ template <>
+ struct less<std::type_info*>:
+ public std::binary_function<std::type_info*, std::type_info*, bool>
+ {
+ bool operator()(std::type_info* lhs, std::type_info* rhs) const
+ {
+ return before(lhs, rhs);
+ }
+ };
+} // std
+
#endif // LL_LLSTL_H
diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h
index 7510cc12ed..0b6862444e 100644
--- a/indra/llcommon/lltypeinfolookup.h
+++ b/indra/llcommon/lltypeinfolookup.h
@@ -12,10 +12,50 @@
#if ! defined(LL_LLTYPEINFOLOOKUP_H)
#define LL_LLTYPEINFOLOOKUP_H
-#include "llsortedvector.h"
+#include <boost/unordered_map.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/optional.hpp>
+#include <functional> // std::binary_function
#include <typeinfo>
/**
+ * The following helper classes are based on the Boost.Unordered documentation:
+ * http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html
+ */
+
+/**
+ * Compute hash for a string passed as const char*
+ */
+struct const_char_star_hash: public std::unary_function<const char*, std::size_t>
+{
+ std::size_t operator()(const char* str) const
+ {
+ std::size_t seed = 0;
+ for ( ; *str; ++str)
+ {
+ boost::hash_combine(seed, *str);
+ }
+ return seed;
+ }
+};
+
+/**
+ * Compute equality for strings passed as const char*
+ *
+ * I (nat) suspect that this is where the default behavior breaks for the
+ * const char* values returned from std::type_info::name(). If you compare the
+ * two const char* pointer values, as a naive, unspecialized implementation
+ * will surely do, they'll compare unequal.
+ */
+struct const_char_star_equal: public std::binary_function<const char*, const char*, bool>
+{
+ bool operator()(const char* lhs, const char* rhs) const
+ {
+ return strcmp(lhs, rhs) == 0;
+ }
+};
+
+/**
* LLTypeInfoLookup is specifically designed for use cases for which you might
* consider std::map<std::type_info*, VALUE>. We have several such data
* structures in the viewer. The trouble with them is that at least on Linux,
@@ -23,88 +63,55 @@
* different load modules will produce different std::type_info*.
* LLTypeInfoLookup contains a workaround to address this issue.
*
- * Specifically, when we don't find the passed std::type_info*,
- * LLTypeInfoLookup performs a linear search over registered entries to
- * compare name() strings. Presuming that this succeeds, we cache the new
- * (previously unrecognized) std::type_info* to speed future lookups.
- *
- * This worst-case fallback search (linear search with string comparison)
- * should only happen the first time we look up a given type from a particular
- * load module other than the one from which we initially registered types.
- * (However, a lookup which wouldn't succeed anyway will always have
- * worst-case performance.) This class is probably best used with less than a
- * few dozen different types.
+ * The API deliberately diverges from std::map in several respects:
+ * * It avoids iterators, not only begin()/end() but also as return values
+ * from insert() and find(). This bypasses transform_iterator overhead.
+ * * Since we literally use compile-time types as keys, the essential insert()
+ * and find() methods accept the key type as a @em template parameter,
+ * accepting and returning value_type as a normal runtime value. This is to
+ * permit future optimization (e.g. compile-time type hashing) without
+ * changing the API.
*/
template <typename VALUE>
class LLTypeInfoLookup
{
+ // Use this for our underlying implementation: lookup by
+ // std::type_info::name() string. This is one of the rare cases in which I
+ // dare use const char* directly, rather than std::string, because I'm
+ // sure that every value returned by std::type_info::name() is static.
+ // HOWEVER, specify our own hash + equality functors: naively comparing
+ // distinct const char* values won't work.
+ typedef boost::unordered_map<const char*, VALUE,
+ const_char_star_hash, const_char_star_equal> impl_map_type;
+
public:
- typedef LLTypeInfoLookup<VALUE> self;
- typedef LLSortedVector<const std::type_info*, VALUE> vector_type;
- typedef typename vector_type::key_type key_type;
- typedef typename vector_type::mapped_type mapped_type;
- typedef typename vector_type::value_type value_type;
- typedef typename vector_type::iterator iterator;
- typedef typename vector_type::const_iterator const_iterator;
+ typedef VALUE value_type;
LLTypeInfoLookup() {}
- iterator begin() { return mVector.begin(); }
- iterator end() { return mVector.end(); }
- const_iterator begin() const { return mVector.begin(); }
- const_iterator end() const { return mVector.end(); }
- bool empty() const { return mVector.empty(); }
- std::size_t size() const { return mVector.size(); }
-
- std::pair<iterator, bool> insert(const std::type_info* key, const VALUE& value)
- {
- return insert(value_type(key, value));
- }
-
- std::pair<iterator, bool> insert(const value_type& pair)
- {
- return mVector.insert(pair);
- }
+ bool empty() const { return mMap.empty(); }
+ std::size_t size() const { return mMap.size(); }
- // const find() forwards to non-const find(): this can alter mVector!
- const_iterator find(const std::type_info* key) const
+ template <typename KEY>
+ bool insert(const value_type& value)
{
- return const_cast<self*>(this)->find(key);
+ // Obtain and store the std::type_info::name() string as the key.
+ // Return just the bool from std::map::insert()'s return pair.
+ return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second;
}
- // non-const find() caches previously-unknown type_info* to speed future
- // lookups.
- iterator find(const std::type_info* key)
+ template <typename KEY>
+ boost::optional<value_type> find() const
{
- iterator found = mVector.find(key);
- if (found != mVector.end())
- {
- // If LLSortedVector::find() found, great, we're done.
- return found;
- }
- // Here we didn't find the passed type_info*. On Linux, though, even
- // for the same type, typeid(sametype) produces a different type_info*
- // when used in different load modules. So the fact that we didn't
- // find the type_info* we seek doesn't mean this type isn't
- // registered. Scan for matching name() string.
- for (typename vector_type::iterator ti(mVector.begin()), tend(mVector.end());
- ti != tend; ++ti)
- {
- if (std::string(ti->first->name()) == key->name())
- {
- // This unrecognized 'key' is for the same type as ti->first.
- // To speed future lookups, insert a new entry that lets us
- // look up ti->second using this same 'key'.
- return insert(key, ti->second).first;
- }
- }
- // We simply have never seen a type with this type_info* from any load
- // module.
- return mVector.end();
+ // Use the std::type_info::name() string as the key.
+ typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name());
+ if (found == mMap.end())
+ return boost::optional<value_type>();
+ return found->second;
}
private:
- vector_type mVector;
+ impl_map_type mMap;
};
#endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index bcc661a920..b12aa8826a 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -29,7 +29,7 @@
const S32 LL_VERSION_MAJOR = 3;
const S32 LL_VERSION_MINOR = 4;
-const S32 LL_VERSION_PATCH = 1;
+const S32 LL_VERSION_PATCH = 2;
const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Developer";