/** * @file llstl.h * @brief helper object & functions for use with the stl. * * $LicenseInfo:firstyear=2003&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 LL_LLSTL_H #define LL_LLSTL_H #include "stdtypes.h" #include #include #include #include #include #include #include #ifdef LL_LINUX // For strcmp #include #endif // Use to compare the first element only of a pair // e.g. typedef std::set, compare_pair > some_pair_set_t; template struct compare_pair_first { bool operator()(const std::pair& a, const std::pair& b) const { return a.first < b.first; } }; template struct compare_pair_greater { bool operator()(const std::pair& a, const std::pair& b) const { if (!(a.first < b.first)) return true; else if (!(b.first < a.first)) return false; else return !(a.second < b.second); } }; // Use to compare the contents of two pointers (e.g. std::string*) template struct compare_pointer_contents { typedef const T* Tptr; bool operator()(const Tptr& a, const Tptr& b) const { return *a < *b; } }; // DeletePointer is a simple helper for deleting all pointers in a container. // The general form is: // // std::for_each(cont.begin(), cont.end(), DeletePointer()); // somemap.clear(); // // Don't forget to clear()! struct DeletePointer { template void operator()(T* ptr) const { delete ptr; } }; struct DeletePointerArray { template void operator()(T* ptr) const { delete[] ptr; } }; // DeletePairedPointer is a simple helper for deleting all pointers in a map. // The general form is: // // std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer()); // somemap.clear(); // Don't leave dangling pointers around struct DeletePairedPointer { template void operator()(T &ptr) const { delete ptr.second; ptr.second = NULL; } }; struct DeletePairedPointerArray { template void operator()(T &ptr) const { delete[] ptr.second; ptr.second = NULL; } }; // Alternate version of the above so that has a more cumbersome // syntax, but it can be used with compositional functors. // NOTE: The functor retuns a bool because msdev bombs during the // composition if you return void. Once we upgrade to a newer // compiler, the second unary_function template parameter can be set // to void. // // Here's a snippet showing how you use this object: // // typedef std::map map_type; // map_type widget_map; // ... // add elements // // delete them all // for_each(widget_map.begin(), // widget_map.end(), // llcompose1(DeletePointerFunctor(), // llselect2nd())); template struct DeletePointerFunctor { bool operator()(T* ptr) const { delete ptr; return true; } }; // See notes about DeleteArray for why you should consider avoiding this. template struct DeleteArrayFunctor { bool operator()(T* ptr) const { delete[] ptr; return true; } }; // CopyNewPointer is a simple helper which accepts a pointer, and // returns a new pointer built with the copy constructor. Example: // // transform(in.begin(), in.end(), out.end(), CopyNewPointer()); struct CopyNewPointer { template T* operator()(const T* ptr) const { return new T(*ptr); } }; 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; // std::map foo; // foo[18] = "there"; // foo[2] = "hello"; // const char* bar = get_ptr_in_map(foo, 2); // bar -> "hello" // const char* baz = get_ptr_in_map(foo, 3); // baz == NULL template inline T* get_ptr_in_map(const std::map& inmap, const K& key) { // Typedef here avoids warnings because of new c++ naming rules. typedef typename std::map::const_iterator map_iter; map_iter iter = inmap.find(key); if(iter == inmap.end()) { return NULL; } else { return iter->second; } }; // helper function which returns true if key is in inmap. template inline bool is_in_map(const std::map& inmap, const K& key) { if(inmap.find(key) == inmap.end()) { return false; } else { return true; } } // Similar to get_ptr_in_map, but for any type with a valid T(0) constructor. // To replace LLSkipMap getIfThere, use: // get_if_there(map, key, 0) // WARNING: Make sure default_value (generally 0) is not a valid map entry! template inline T get_if_there(const std::map& inmap, const K& key, T default_value) { // Typedef here avoids warnings because of new c++ naming rules. typedef typename std::map::const_iterator map_iter; map_iter iter = inmap.find(key); if(iter == inmap.end()) { return default_value; } else { return iter->second; } }; // Useful for replacing the removeObj() functionality of LLDynamicArray // Example: // for (std::vector::iterator iter = mList.begin(); iter != mList.end(); ) // { // if ((*iter)->isMarkedForRemoval()) // iter = vector_replace_with_last(mList, iter); // else // ++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()) { return iter; } else if (iter == last) { invec.pop_back(); return invec.end(); } else { *iter = *last; invec.pop_back(); return iter; } }; // Example: // vector_replace_with_last(mList, x); template inline bool vector_replace_with_last(std::vector& invec, const T& val) { typename std::vector::iterator iter = std::find(invec.begin(), invec.end(), val); if (iter != invec.end()) { typename std::vector::iterator last = invec.end(); --last; *iter = *last; invec.pop_back(); return true; } return false; } // Append N elements to the vector and return a pointer to the first new element. template inline T* vector_append(std::vector& invec, S32 N) { auto sz = invec.size(); invec.resize(sz+N); return &(invec[sz]); } // call function f to n members starting at first. similar to std::for_each template Function ll_for_n(InputIter first, Size n, Function f) { for ( ; n > 0; --n, ++first) f(*first); return f; } // copy first to result n times, incrementing each as we go template OutputIter ll_copy_n(InputIter first, Size n, OutputIter result) { for ( ; n > 0; --n, ++result, ++first) *result = *first; return result; } // set *result = op(*f) for n elements of f template OutputIter ll_transform_n( InputIter first, Size n, OutputIter result, UnaryOp op) { for ( ; n > 0; --n, ++result, ++first) *result = op(*first); return result; } /* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1996-1998 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */ // helper to deal with the fact that MSDev does not package // select... with the stl. Look up usage on the sgi website. template struct _LLSelect1st { const auto& operator()(const _Pair& __x) const { return __x.first; } }; template struct _LLSelect2nd { const auto& operator()(const _Pair& __x) const { return __x.second; } }; template struct llselect1st : public _LLSelect1st<_Pair> {}; template struct llselect2nd : public _LLSelect2nd<_Pair> {}; // helper to deal with the fact that MSDev does not package // compose... with the stl. Look up usage on the sgi website. template class ll_unary_compose { protected: _Operation1 __op1; _Operation2 __op2; public: ll_unary_compose(const _Operation1& __x, const _Operation2& __y) : __op1(__x), __op2(__y) {} template auto operator()(const _Op2Arg& __x) const { return __op1(__op2(__x)); } }; template inline ll_unary_compose<_Operation1,_Operation2> llcompose1(const _Operation1& __op1, const _Operation2& __op2) { return ll_unary_compose<_Operation1,_Operation2>(__op1, __op2); } template class ll_binary_compose { protected: _Operation1 _M_op1; _Operation2 _M_op2; _Operation3 _M_op3; public: ll_binary_compose(const _Operation1& __x, const _Operation2& __y, const _Operation3& __z) : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } template auto operator()(const OP2ARG& __x) const { return _M_op1(_M_op2(__x), _M_op3(__x)); } }; template inline ll_binary_compose<_Operation1, _Operation2, _Operation3> llcompose2(const _Operation1& __op1, const _Operation2& __op2, const _Operation3& __op3) { return ll_binary_compose<_Operation1,_Operation2,_Operation3> (__op1, __op2, __op3); } // helpers to deal with the fact that MSDev does not package // bind... with the stl. Again, this is from sgi. template class llbinder1st { protected: _Operation op; _Arg1 value; public: llbinder1st(const _Operation& __x, const _Arg1& __y) : op(__x), value(__y) {} template auto operator()(const _Arg2& __x) const { return op(value, __x); } }; template inline auto llbind1st(const _Operation& __oper, const _Tp& __x) { return llbinder1st<_Operation, _Tp>(__oper, __x); } template class llbinder2nd { protected: _Operation op; _Arg2 value; public: llbinder2nd(const _Operation& __x, const _Arg2& __y) : op(__x), value(__y) {} template auto operator()(const _Arg1& __x) const { return op(__x, value); } }; template inline auto llbind2nd(const _Operation& __oper, const _Tp& __x) { return llbinder2nd<_Operation, _Tp>(__oper, __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 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 { bool operator()(const std::type_info* lhs, const std::type_info* rhs) const { return before(lhs, rhs); } }; template <> struct less { 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 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