From 3fd640a6e3dea7a3551c239323d782fb082e1dbd Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Sun, 23 Dec 2012 12:27:25 -0800 Subject: SH-3468 WIP add memory tracking base class fixed crash on exit by making LLInstanceTracker iterators use atomic iterator nesting count for thread safety --- indra/llcommon/llstl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llcommon/llstl.h') diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index d3941e1bc9..424138dad1 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From a2e22732f195dc075a733c79f15156752f522a43 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Tue, 30 Jul 2013 19:13:45 -0700 Subject: Summer cleaning - removed a lot of llcommon dependencies to speed up build times consolidated most indra-specific constants in llcommon under indra_constants.h fixed issues with operations on mixed unit types (implicit and explicit) made LL_INFOS() style macros variadic in order to subsume other logging methods such as ll_infos added optional tag output to error recorders --- indra/llcommon/llstl.h | 199 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 193 insertions(+), 6 deletions(-) (limited to 'indra/llcommon/llstl.h') diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 424138dad1..143e71f40c 100755 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -33,7 +33,6 @@ #include #include #include -#include #include // Use to compare the first element only of a pair @@ -125,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 map_type; // map_type widget_map; @@ -170,6 +169,49 @@ struct CopyNewPointer } }; +template +void delete_and_clear(std::list& list) +{ + std::for_each(list.begin(), list.end(), DeletePointer()); + list.clear(); +} + +template +void delete_and_clear(std::vector& vector) +{ + std::for_each(vector.begin(), vector.end(), DeletePointer()); + vector.clear(); +} + +template +void delete_and_clear(std::set& set) +{ + std::for_each(set.begin(), set.end(), DeletePointer()); + set.clear(); +} + +template +void delete_and_clear(std::map& map) +{ + std::for_each(map.begin(), map.end(), DeletePairedPointer()); + map.clear(); +} + +template +void delete_and_clear(T*& ptr) +{ + delete ptr; + ptr = NULL; +} + + +template +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; @@ -229,7 +271,6 @@ inline T get_if_there(const std::map& inmap, const K& key, T default_value) } }; -// Useful for replacing the removeObj() functionality of LLDynamicArray // Example: // for (std::vector::iterator iter = mList.begin(); iter != mList.end(); ) // { @@ -238,8 +279,8 @@ inline T get_if_there(const std::map& inmap, const K& key, T default_value) // else // ++iter; // } -template -inline Iter vector_replace_with_last(std::vector& invec, Iter iter) +template +inline typename std::vector::iterator vector_replace_with_last(std::vector& invec, typename std::vector::iterator iter) { typename std::vector::iterator last = invec.end(); --last; if (iter == invec.end()) @@ -259,7 +300,6 @@ inline Iter vector_replace_with_last(std::vector& invec, Iter iter) } }; -// Useful for replacing the removeObj() functionality of LLDynamicArray // Example: // vector_replace_with_last(mList, x); template @@ -522,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 +struct ll_template_cast_impl +{ + T operator()(U) + { + return 0; + } +}; + +/** + * ll_template_cast(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 + * void somefunc(const REALCLASS& instance) + * { + * const SpecialClass* ptr = ll_template_cast(&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(&other); + * @endcode + * to say nothing of this: + * @code + * void function(int); + * SpecialClass* ptr = dynamic_cast(&function); + * @endcode + * ll_template_cast handles these kinds of cases by returning 0. + */ +template +T ll_template_cast(U value) +{ + return ll_template_cast_impl()(value); +} + +/** + * Implementation for ll_template_cast() (q.v.). + * + * Implementation for identical types: return same value. + */ +template +struct ll_template_cast_impl +{ + T operator()(T value) + { + return value; + } +}; + +/** + * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of + * type @c source, ll_template_cast(s) will return @c s -- + * presuming that @c source can be converted to @c dest by the normal rules of + * C++. + * + * By default, ll_template_cast(s) 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(&myFoo); + * @endcode + * + * Here @c fooptr will be 0 because &myFoo is of type Foo* + * -- @em not const Foo*. (Declaring const Foo myFoo; 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(&object); + * @endcode + * + * Here @c ptr will be 0 because &object is of type + * Subclass* rather than Base*. 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(&object); + * @endcode + * + * However, as noted earlier, this is easily fooled: + * @code + * const Base* ptr = ll_template_cast(&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 LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*) + * because that's not permitted by normal C++ assignment anyway.) + */ +#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \ +template <> \ +struct ll_template_cast_impl \ +{ \ + DEST operator()(SOURCE wrapper) \ + { \ + return wrapper; \ + } \ +} + + #endif // LL_LLSTL_H -- cgit v1.2.3