summaryrefslogtreecommitdiff
path: root/indra/llcommon/llstl.h
diff options
context:
space:
mode:
authorRichard Linden <none@none>2013-11-11 19:17:49 -0800
committerRichard Linden <none@none>2013-11-11 19:17:49 -0800
commit17e9c872ada0cd1d3bf5c16887ee7f220f3a10c7 (patch)
tree93f36acc00695d7b4ee2e43d08ce790358966f38 /indra/llcommon/llstl.h
parentebc9bcbf69f7a519677a6522979a6bf6cbb04bb8 (diff)
parent1983f52ce5211c02a55f5cabd86962eea3a22084 (diff)
Automated merge with http://bitbucket.org/lindenlab/viewer-release
Diffstat (limited to 'indra/llcommon/llstl.h')
-rwxr-xr-xindra/llcommon/llstl.h200
1 files changed, 194 insertions, 6 deletions
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index d3941e1bc9..143e71f40c 100755
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -31,8 +31,8 @@
#include <algorithm>
#include <map>
#include <vector>
+#include <list>
#include <set>
-#include <deque>
#include <typeinfo>
// Use to compare the first element only of a pair
@@ -124,7 +124,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;
@@ -169,6 +169,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;
@@ -228,7 +271,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(); )
// {
@@ -237,8 +279,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())
@@ -258,7 +300,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>
@@ -521,4 +562,151 @@ namespace std
};
} // 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