summaryrefslogtreecommitdiff
path: root/indra/llcommon/llstl.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llstl.h')
-rwxr-xr-x[-rw-r--r--]indra/llcommon/llstl.h288
1 files changed, 261 insertions, 27 deletions
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 788617953e..02f10fa2ba 100644..100755
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -2,31 +2,25 @@
* @file llstl.h
* @brief helper object & functions for use with the stl.
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -37,8 +31,9 @@
#include <algorithm>
#include <map>
#include <vector>
+#include <list>
#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;
@@ -103,6 +98,7 @@ struct DeletePointerArray
// The general form is:
//
// std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer());
+// somemap.clear(); // Don't leave dangling pointers around
struct DeletePairedPointer
{
@@ -129,7 +125,7 @@ struct DeletePairedPointerArray
// compiler, the second unary_function template parameter can be set
// to void.
//
-// Here's a snippit showing how you use this object:
+// Here's a snippet showing how you use this object:
//
// typedef std::map<int, widget*> map_type;
// map_type widget_map;
@@ -174,6 +170,49 @@ struct CopyNewPointer
}
};
+template<typename T, typename ALLOC>
+void delete_and_clear(std::list<T*, ALLOC>& list)
+{
+ std::for_each(list.begin(), list.end(), DeletePointer());
+ list.clear();
+}
+
+template<typename T, typename ALLOC>
+void delete_and_clear(std::vector<T*, ALLOC>& vector)
+{
+ std::for_each(vector.begin(), vector.end(), DeletePointer());
+ vector.clear();
+}
+
+template<typename T, typename COMPARE, typename ALLOC>
+void delete_and_clear(std::set<T*, COMPARE, ALLOC>& set)
+{
+ std::for_each(set.begin(), set.end(), DeletePointer());
+ set.clear();
+}
+
+template<typename K, typename V, typename COMPARE, typename ALLOC>
+void delete_and_clear(std::map<K, V*, COMPARE, ALLOC>& map)
+{
+ std::for_each(map.begin(), map.end(), DeletePairedPointer());
+ map.clear();
+}
+
+template<typename T>
+void delete_and_clear(T*& ptr)
+{
+ delete ptr;
+ ptr = NULL;
+}
+
+
+template<typename T>
+void delete_and_clear_array(T*& ptr)
+{
+ delete[] ptr;
+ ptr = NULL;
+}
+
// Simple function to help with finding pointers in maps.
// For example:
// typedef map_t;
@@ -233,7 +272,6 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
}
};
-// Useful for replacing the removeObj() functionality of LLDynamicArray
// Example:
// for (std::vector<T>::iterator iter = mList.begin(); iter != mList.end(); )
// {
@@ -242,8 +280,8 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
// else
// ++iter;
// }
-template <typename T, typename Iter>
-inline Iter vector_replace_with_last(std::vector<T>& invec, Iter iter)
+template <typename T>
+inline typename std::vector<T>::iterator vector_replace_with_last(std::vector<T>& invec, typename std::vector<T>::iterator iter)
{
typename std::vector<T>::iterator last = invec.end(); --last;
if (iter == invec.end())
@@ -263,7 +301,6 @@ inline Iter vector_replace_with_last(std::vector<T>& invec, Iter iter)
}
};
-// Useful for replacing the removeObj() functionality of LLDynamicArray
// Example:
// vector_replace_with_last(mList, x);
template <typename T>
@@ -476,4 +513,201 @@ 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
+
+
+/**
+ * Implementation for ll_template_cast() (q.v.).
+ *
+ * Default implementation: trying to cast two completely unrelated types
+ * returns 0. Typically you'd specify T and U as pointer types, but in fact T
+ * can be any type that can be initialized with 0.
+ */
+template <typename T, typename U>
+struct ll_template_cast_impl
+{
+ T operator()(U)
+ {
+ return 0;
+ }
+};
+
+/**
+ * ll_template_cast<T>(some_value) is for use in a template function when
+ * some_value might be of arbitrary type, but you want to recognize type T
+ * specially.
+ *
+ * It's designed for use with pointer types. Example:
+ * @code
+ * struct SpecialClass
+ * {
+ * void someMethod(const std::string&) const;
+ * };
+ *
+ * template <class REALCLASS>
+ * void somefunc(const REALCLASS& instance)
+ * {
+ * const SpecialClass* ptr = ll_template_cast<const SpecialClass*>(&instance);
+ * if (ptr)
+ * {
+ * ptr->someMethod("Call method only available on SpecialClass");
+ * }
+ * }
+ * @endcode
+ *
+ * Why is this better than dynamic_cast<>? Because unless OtherClass is
+ * polymorphic, the following won't even compile (gcc 4.0.1):
+ * @code
+ * OtherClass other;
+ * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&other);
+ * @endcode
+ * to say nothing of this:
+ * @code
+ * void function(int);
+ * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&function);
+ * @endcode
+ * ll_template_cast handles these kinds of cases by returning 0.
+ */
+template <typename T, typename U>
+T ll_template_cast(U value)
+{
+ return ll_template_cast_impl<T, U>()(value);
+}
+
+/**
+ * Implementation for ll_template_cast() (q.v.).
+ *
+ * Implementation for identical types: return same value.
+ */
+template <typename T>
+struct ll_template_cast_impl<T, T>
+{
+ T operator()(T value)
+ {
+ return value;
+ }
+};
+
+/**
+ * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of
+ * type @c source, <tt>ll_template_cast<dest>(s)</tt> will return @c s --
+ * presuming that @c source can be converted to @c dest by the normal rules of
+ * C++.
+ *
+ * By default, <tt>ll_template_cast<dest>(s)</tt> will return 0 unless @c s's
+ * type is literally identical to @c dest. (This is because of the
+ * straightforward application of template specialization rules.) That can
+ * lead to surprising results, e.g.:
+ *
+ * @code
+ * Foo myFoo;
+ * const Foo* fooptr = ll_template_cast<const Foo*>(&myFoo);
+ * @endcode
+ *
+ * Here @c fooptr will be 0 because <tt>&myFoo</tt> is of type <tt>Foo*</tt>
+ * -- @em not <tt>const Foo*</tt>. (Declaring <tt>const Foo myFoo;</tt> would
+ * force the compiler to do the right thing.)
+ *
+ * More disappointingly:
+ * @code
+ * struct Base {};
+ * struct Subclass: public Base {};
+ * Subclass object;
+ * Base* ptr = ll_template_cast<Base*>(&object);
+ * @endcode
+ *
+ * Here @c ptr will be 0 because <tt>&object</tt> is of type
+ * <tt>Subclass*</tt> rather than <tt>Base*</tt>. We @em want this cast to
+ * succeed, but without our help ll_template_cast can't recognize it.
+ *
+ * The following would suffice:
+ * @code
+ * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*);
+ * ...
+ * Base* ptr = ll_template_cast<Base*>(&object);
+ * @endcode
+ *
+ * However, as noted earlier, this is easily fooled:
+ * @code
+ * const Base* ptr = ll_template_cast<const Base*>(&object);
+ * @endcode
+ * would still produce 0 because we haven't yet seen:
+ * @code
+ * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*);
+ * @endcode
+ *
+ * @TODO
+ * This macro should use Boost type_traits facilities for stripping and
+ * re-adding @c const and @c volatile qualifiers so that invoking
+ * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all
+ * permitted permutations. It's really not fair to the coder to require
+ * separate:
+ * @code
+ * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*);
+ * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*);
+ * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*);
+ * @endcode
+ *
+ * (Naturally we omit <tt>LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*)</tt>
+ * because that's not permitted by normal C++ assignment anyway.)
+ */
+#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \
+template <> \
+struct ll_template_cast_impl<DEST, SOURCE> \
+{ \
+ DEST operator()(SOURCE wrapper) \
+ { \
+ return wrapper; \
+ } \
+}
+
+
#endif // LL_LLSTL_H