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/linden_common.h4
-rw-r--r--indra/llcommon/llapr.h2
-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/llsdserialize.cpp5
-rw-r--r--indra/llcommon/llstl.h51
-rw-r--r--indra/llcommon/llstring.cpp3
-rw-r--r--indra/llcommon/llthread.cpp7
-rw-r--r--indra/llcommon/llthread.h5
-rw-r--r--indra/llcommon/lltypeinfolookup.h141
-rw-r--r--indra/llcommon/lluri.cpp36
-rw-r--r--indra/llcommon/llversionviewer.h2
-rw-r--r--indra/llcommon/tests/bitpack_test.cpp1
-rw-r--r--indra/llcommon/tests/lluri_test.cpp94
-rw-r--r--indra/llcommon/tests/reflection_test.cpp2
18 files changed, 473 insertions, 145 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/linden_common.h b/indra/llcommon/linden_common.h
index 5cfcdab41c..f0a5603d06 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -59,4 +59,8 @@
#include "llerror.h"
#include "llfile.h"
+// Boost 1.45 had version 2 as the default for the filesystem library,
+// 1.48 has version 3 as the default. Keep compatibility for now.
+#define BOOST_FILESYSTEM_VERSION 2
+
#endif
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index af33ce666f..034546c3f3 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -168,7 +168,7 @@ public:
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
- Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
+ Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
private:
apr_uint32_t mData;
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/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 7f4f670ed0..6b549e4b6f 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -1451,9 +1451,12 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
}
case LLSD::TypeUUID:
+ {
ostr.put('u');
- ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
+ LLSD::UUID value = data.asUUID();
+ ostr.write((const char*)(&value.mData), UUID_BYTES);
break;
+ }
case LLSD::TypeString:
ostr.put('s');
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/llstring.cpp b/indra/llcommon/llstring.cpp
index fa0eb9f72c..0c32679744 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -47,7 +47,8 @@ std::string ll_safe_string(const char* in)
std::string ll_safe_string(const char* in, S32 maxlen)
{
- if(in) return std::string(in, maxlen);
+ if(in && maxlen > 0 ) return std::string(in, maxlen);
+
return std::string();
}
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index c2fbb544a8..1d56a52c32 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -71,6 +71,13 @@ LL_COMMON_API void assert_main_thread()
}
}
+void LLThread::registerThreadID()
+{
+#if !LL_DARWIN
+ sThreadID = ++sIDIter;
+#endif
+}
+
//
// Handed to the APR thread creation function
//
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 115bf47553..5c8bbca2ca 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -88,6 +88,11 @@ public:
U32 getID() const { return mID; }
+ // Called by threads *not* created via LLThread to register some
+ // internal state used by LLMutex. You must call this once early
+ // in the running thread to prevent collisions with the main thread.
+ static void registerThreadID();
+
private:
BOOL mPaused;
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/lluri.cpp b/indra/llcommon/lluri.cpp
index b39ea0c6f2..21456a599b 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -37,6 +37,8 @@
// system includes
#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string/find_iterator.hpp>
+#include <boost/algorithm/string/finder.hpp>
void encode_character(std::ostream& ostr, std::string::value_type val)
{
@@ -317,7 +319,7 @@ LLURI LLURI::buildHTTP(const std::string& prefix,
const LLSD& path)
{
LLURI result;
-
+
// TODO: deal with '/' '?' '#' in host_port
if (prefix.find("://") != prefix.npos)
{
@@ -342,15 +344,41 @@ LLURI LLURI::buildHTTP(const std::string& prefix,
result.mEscapedPath += "/" + escapePathComponent(it->asString());
}
}
- else if(path.isString())
+ else if (path.isString())
{
- result.mEscapedPath += "/" + escapePathComponent(path.asString());
+ std::string pathstr(path);
+ // Trailing slash is significant in HTTP land. If caller specified,
+ // make a point of preserving.
+ std::string last_slash;
+ std::string::size_type len(pathstr.length());
+ if (len && pathstr[len-1] == '/')
+ {
+ last_slash = "/";
+ }
+
+ // Escape every individual path component, recombining with slashes.
+ for (boost::split_iterator<std::string::const_iterator>
+ ti(pathstr, boost::first_finder("/")), tend;
+ ti != tend; ++ti)
+ {
+ // Eliminate a leading slash or duplicate slashes anywhere. (Extra
+ // slashes show up here as empty components.) This test also
+ // eliminates a trailing slash, hence last_slash above.
+ if (! ti->empty())
+ {
+ result.mEscapedPath
+ += "/" + escapePathComponent(std::string(ti->begin(), ti->end()));
+ }
+ }
+
+ // Reinstate trailing slash, if any.
+ result.mEscapedPath += last_slash;
}
else if(path.isUndefined())
{
// do nothing
}
- else
+ else
{
llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type"
<< path.type() << llendl;
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index bcc661a920..91008eb5d6 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 = 3;
const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp
index 05289881d0..4c3bc674af 100644
--- a/indra/llcommon/tests/bitpack_test.cpp
+++ b/indra/llcommon/tests/bitpack_test.cpp
@@ -95,6 +95,7 @@ namespace tut
ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);
unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4);
+ ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize);
}
// U32 packing
diff --git a/indra/llcommon/tests/lluri_test.cpp b/indra/llcommon/tests/lluri_test.cpp
index f6d4221256..4c64f15ca7 100644
--- a/indra/llcommon/tests/lluri_test.cpp
+++ b/indra/llcommon/tests/lluri_test.cpp
@@ -58,12 +58,12 @@ namespace tut
ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1);
}
};
-
+
typedef test_group<URITestData> URITestGroup;
typedef URITestGroup::object URITestObject;
URITestGroup uriTestGroup("LLURI");
-
+
template<> template<>
void URITestObject::test<1>()
{
@@ -89,14 +89,14 @@ namespace tut
template<> template<>
void URITestObject::test<2>()
{
- // empty string
+ set_test_name("empty string");
checkParts(LLURI(""), "", "", "", "");
}
-
+
template<> template<>
void URITestObject::test<3>()
{
- // no scheme
+ set_test_name("no scheme");
checkParts(LLURI("foo"), "", "foo", "", "");
checkParts(LLURI("foo%3A"), "", "foo:", "", "");
}
@@ -104,7 +104,7 @@ namespace tut
template<> template<>
void URITestObject::test<4>()
{
- // scheme w/o paths
+ set_test_name("scheme w/o paths");
checkParts(LLURI("mailto:zero@ll.com"),
"mailto", "zero@ll.com", "", "");
checkParts(LLURI("silly://abc/def?foo"),
@@ -114,16 +114,16 @@ namespace tut
template<> template<>
void URITestObject::test<5>()
{
- // authority section
+ set_test_name("authority section");
checkParts(LLURI("http:///"),
"http", "///", "", "/");
-
+
checkParts(LLURI("http://abc"),
"http", "//abc", "abc", "");
-
+
checkParts(LLURI("http://a%2Fb/cd"),
"http", "//a/b/cd", "a/b", "/cd");
-
+
checkParts(LLURI("http://host?"),
"http", "//host?", "host", "");
}
@@ -131,13 +131,13 @@ namespace tut
template<> template<>
void URITestObject::test<6>()
{
- // path section
+ set_test_name("path section");
checkParts(LLURI("http://host/a/b/"),
"http", "//host/a/b/", "host", "/a/b/");
-
+
checkParts(LLURI("http://host/a%3Fb/"),
"http", "//host/a?b/", "host", "/a?b/");
-
+
checkParts(LLURI("http://host/a:b/"),
"http", "//host/a:b/", "host", "/a:b/");
}
@@ -145,16 +145,16 @@ namespace tut
template<> template<>
void URITestObject::test<7>()
{
- // query string
+ set_test_name("query string");
checkParts(LLURI("http://host/?"),
"http", "//host/?", "host", "/", "");
-
+
checkParts(LLURI("http://host/?x"),
"http", "//host/?x", "host", "/", "x");
-
+
checkParts(LLURI("http://host/??"),
"http", "//host/??", "host", "/", "?");
-
+
checkParts(LLURI("http://host/?%3F"),
"http", "//host/??", "host", "/", "?");
}
@@ -167,19 +167,44 @@ namespace tut
path.append("123");
checkParts(LLURI::buildHTTP("host", path),
"http", "//host/x/123", "host", "/x/123");
-
+
LLSD query;
query["123"] = "12";
query["abcd"] = "abc";
checkParts(LLURI::buildHTTP("host", path, query),
"http", "//host/x/123?123=12&abcd=abc",
"host", "/x/123", "123=12&abcd=abc");
+
+ ensure_equals(LLURI::buildHTTP("host", "").asString(),
+ "http://host");
+ ensure_equals(LLURI::buildHTTP("host", "/").asString(),
+ "http://host/");
+ ensure_equals(LLURI::buildHTTP("host", "//").asString(),
+ "http://host/");
+ ensure_equals(LLURI::buildHTTP("host", "dir name").asString(),
+ "http://host/dir%20name");
+ ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(),
+ "http://host/dir%20name/");
+ ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(),
+ "http://host/dir%20name");
+ ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(),
+ "http://host/dir%20name/");
+ ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(),
+ "http://host/dir%20name/subdir%20name");
+ ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(),
+ "http://host/dir%20name/subdir%20name/");
+ ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(),
+ "http://host/dir%20name/subdir%20name");
+ ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(),
+ "http://host/dir%20name/subdir%20name/");
+ ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(),
+ "http://host/dir%20name/subdir%20name/");
}
template<> template<>
void URITestObject::test<9>()
{
- // test unescaped path components
+ set_test_name("test unescaped path components");
LLSD path;
path.append("x@*//*$&^");
path.append("123");
@@ -190,7 +215,7 @@ namespace tut
template<> template<>
void URITestObject::test<10>()
{
- // test unescaped query components
+ set_test_name("test unescaped query components");
LLSD path;
path.append("x");
path.append("123");
@@ -205,7 +230,7 @@ namespace tut
template<> template<>
void URITestObject::test<11>()
{
- // test unescaped host components
+ set_test_name("test unescaped host components");
LLSD path;
path.append("x");
path.append("123");
@@ -216,16 +241,16 @@ namespace tut
"http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc",
"hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc");
}
-
+
template<> template<>
void URITestObject::test<12>()
{
- // test funky host_port values that are actually prefixes
-
+ set_test_name("test funky host_port values that are actually prefixes");
+
checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()),
"http", "//example.com:8080",
"example.com:8080", "");
-
+
checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()),
"http", "//example.com:8080/",
"example.com:8080", "/");
@@ -242,7 +267,7 @@ namespace tut
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789"
"-._~";
- // test escape
+ set_test_name("test escape");
ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67");
ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40");
ensure_equals("escaping as query variable",
@@ -259,13 +284,12 @@ namespace tut
cedilla.push_back( (char)0xA7 );
ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7");
}
-
+
template<> template<>
void URITestObject::test<14>()
{
- // make sure escape and unescape of empty strings return empty
- // strings.
+ set_test_name("make sure escape and unescape of empty strings return empty strings.");
std::string uri_esc(LLURI::escape(""));
ensure("escape string empty", uri_esc.empty());
std::string uri_raw(LLURI::unescape(""));
@@ -275,7 +299,7 @@ namespace tut
template<> template<>
void URITestObject::test<15>()
{
- // do some round-trip tests
+ set_test_name("do some round-trip tests");
escapeRoundTrip("http://secondlife.com");
escapeRoundTrip("http://secondlife.com/url with spaces");
escapeRoundTrip("http://bad[domain]name.com/");
@@ -286,7 +310,7 @@ namespace tut
template<> template<>
void URITestObject::test<16>()
{
- // Test the default escaping
+ set_test_name("Test the default escaping");
// yes -- this mangles the url. This is expected behavior
std::string simple("http://secondlife.com");
ensure_equals(
@@ -302,7 +326,7 @@ namespace tut
template<> template<>
void URITestObject::test<17>()
{
- // do some round-trip tests with very long strings.
+ set_test_name("do some round-trip tests with very long strings.");
escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six");
escapeRoundTrip(
"'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale"
@@ -322,7 +346,7 @@ namespace tut
"D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n");
}
-
+
template<> template<>
void URITestObject::test<18>()
{
@@ -335,7 +359,7 @@ namespace tut
ensure_equals("pathmap", u.pathArray()[1].asString(), "login");
ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test");
ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester");
-
+
u = LLURI("secondlife://Da Boom/128/128/128");
// if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority
ensure_equals("scheme", u.scheme(), "secondlife");
@@ -350,7 +374,7 @@ namespace tut
template<> template<>
void URITestObject::test<19>()
{
- // Parse about: schemes
+ set_test_name("Parse about: schemes");
LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78");
ensure_equals("scheme", u.scheme(), "about");
ensure_equals("authority", u.authority(), "");
diff --git a/indra/llcommon/tests/reflection_test.cpp b/indra/llcommon/tests/reflection_test.cpp
index 59491cd1fe..8980ebb1f1 100644
--- a/indra/llcommon/tests/reflection_test.cpp
+++ b/indra/llcommon/tests/reflection_test.cpp
@@ -207,7 +207,7 @@ namespace tut
const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception.
// useless op to get rid of compiler warning.
- reflective = NULL;
+ reflective = reflective;
}
catch(...)
{