/* Copyright (C) 2009-2010 Electronic Arts, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /////////////////////////////////////////////////////////////////////////////// // EASTL/set.h // // Copyright (c) 2005, Electronic Arts. All rights reserved. // Written by Paul Pedriana. ////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_SET_H #define EASTL_SET_H #include #include #include #include namespace eastl { /// EASTL_SET_DEFAULT_NAME /// /// Defines a default container name in the absence of a user-provided name. /// #ifndef EASTL_SET_DEFAULT_NAME #define EASTL_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " set" // Unless the user overrides something, this is "EASTL set". #endif /// EASTL_MULTISET_DEFAULT_NAME /// /// Defines a default container name in the absence of a user-provided name. /// #ifndef EASTL_MULTISET_DEFAULT_NAME #define EASTL_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " multiset" // Unless the user overrides something, this is "EASTL multiset". #endif /// EASTL_SET_DEFAULT_ALLOCATOR /// #ifndef EASTL_SET_DEFAULT_ALLOCATOR #define EASTL_SET_DEFAULT_ALLOCATOR allocator_type(EASTL_SET_DEFAULT_NAME) #endif /// EASTL_MULTISET_DEFAULT_ALLOCATOR /// #ifndef EASTL_MULTISET_DEFAULT_ALLOCATOR #define EASTL_MULTISET_DEFAULT_ALLOCATOR allocator_type(EASTL_MULTISET_DEFAULT_NAME) #endif /// set /// /// Implements a canonical set. /// /// The large majority of the implementation of this class is found in the rbtree /// base class. We control the behaviour of rbtree via template parameters. /// /// Note that the 'bMutableIterators' template parameter to rbtree is set to false. /// This means that set::iterator is const and the same as set::const_iterator. /// This is by design and it follows the C++ standard defect report recommendation. /// If the user wants to modify a container element, the user needs to either use /// mutable data members or use const_cast on the iterator's data member. Both of /// these solutions are recommended by the C++ standard defect report. /// To consider: Expose the bMutableIterators template policy here at the set level /// so the user can have non-const set iterators via a template parameter. /// /// Pool allocation /// If you want to make a custom memory pool for a set container, your pool /// needs to contain items of type set::node_type. So if you have a memory /// pool that has a constructor that takes the size of pool items and the /// count of pool items, you would do this (assuming that MemoryPool implements /// the Allocator interface): /// typedef set, MemoryPool> WidgetSet; // Delare your WidgetSet type. /// MemoryPool myPool(sizeof(WidgetSet::node_type), 100); // Make a pool of 100 Widget nodes. /// WidgetSet mySet(&myPool); // Create a map that uses the pool. /// template , typename Allocator = EASTLAllocatorType> class set : public rbtree, false, true> { public: typedef rbtree, false, true> base_type; typedef set this_type; typedef typename base_type::size_type size_type; typedef typename base_type::value_type value_type; typedef typename base_type::iterator iterator; typedef typename base_type::const_iterator const_iterator; typedef typename base_type::reverse_iterator reverse_iterator; typedef typename base_type::const_reverse_iterator const_reverse_iterator; typedef typename base_type::allocator_type allocator_type; // Other types are inherited from the base class. using base_type::begin; using base_type::end; using base_type::find; using base_type::lower_bound; using base_type::upper_bound; using base_type::mCompare; public: set(const allocator_type& allocator = EASTL_SET_DEFAULT_ALLOCATOR); set(const Compare& compare, const allocator_type& allocator = EASTL_SET_DEFAULT_ALLOCATOR); set(const this_type& x); template set(Iterator itBegin, Iterator itEnd); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. public: size_type erase(const Key& k); iterator erase(iterator position); iterator erase(iterator first, iterator last); reverse_iterator erase(reverse_iterator position); reverse_iterator erase(reverse_iterator first, reverse_iterator last); size_type count(const Key& k) const; eastl::pair equal_range(const Key& k); eastl::pair equal_range(const Key& k) const; }; // set /// multiset /// /// Implements a canonical multiset. /// /// The large majority of the implementation of this class is found in the rbtree /// base class. We control the behaviour of rbtree via template parameters. /// /// See notes above in 'set' regarding multable iterators. /// /// Pool allocation /// If you want to make a custom memory pool for a multiset container, your pool /// needs to contain items of type multiset::node_type. So if you have a memory /// pool that has a constructor that takes the size of pool items and the /// count of pool items, you would do this (assuming that MemoryPool implements /// the Allocator interface): /// typedef multiset, MemoryPool> WidgetSet; // Delare your WidgetSet type. /// MemoryPool myPool(sizeof(WidgetSet::node_type), 100); // Make a pool of 100 Widget nodes. /// WidgetSet mySet(&myPool); // Create a map that uses the pool. /// template , typename Allocator = EASTLAllocatorType> class multiset : public rbtree, false, false> { public: typedef rbtree, false, false> base_type; typedef multiset this_type; typedef typename base_type::size_type size_type; typedef typename base_type::value_type value_type; typedef typename base_type::iterator iterator; typedef typename base_type::const_iterator const_iterator; typedef typename base_type::reverse_iterator reverse_iterator; typedef typename base_type::const_reverse_iterator const_reverse_iterator; typedef typename base_type::allocator_type allocator_type; // Other types are inherited from the base class. using base_type::begin; using base_type::end; using base_type::find; using base_type::lower_bound; using base_type::upper_bound; using base_type::mCompare; public: multiset(const allocator_type& allocator = EASTL_MULTISET_DEFAULT_ALLOCATOR); multiset(const Compare& compare, const allocator_type& allocator = EASTL_MULTISET_DEFAULT_ALLOCATOR); multiset(const this_type& x); template multiset(Iterator itBegin, Iterator itEnd); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. public: size_type erase(const Key& k); iterator erase(iterator position); iterator erase(iterator first, iterator last); reverse_iterator erase(reverse_iterator position); reverse_iterator erase(reverse_iterator first, reverse_iterator last); size_type count(const Key& k) const; eastl::pair equal_range(const Key& k); eastl::pair equal_range(const Key& k) const; /// equal_range_small /// This is a special version of equal_range which is optimized for the /// case of there being few or no duplicated keys in the tree. eastl::pair equal_range_small(const Key& k); eastl::pair equal_range_small(const Key& k) const; }; // multiset /////////////////////////////////////////////////////////////////////// // set /////////////////////////////////////////////////////////////////////// template inline set::set(const allocator_type& allocator) : base_type(allocator) { // Empty } template inline set::set(const Compare& compare, const allocator_type& allocator) : base_type(compare, allocator) { // Empty } template inline set::set(const this_type& x) : base_type(x) { // Empty } template template inline set::set(Iterator itBegin, Iterator itEnd) : base_type(itBegin, itEnd, Compare(), EASTL_SET_DEFAULT_ALLOCATOR) { // Empty } template inline typename set::size_type set::erase(const Key& k) { const iterator it(find(k)); if(it != end()) // If it exists... { base_type::erase(it); return 1; } return 0; } template inline typename set::iterator set::erase(iterator position) { // We need to provide this version because we override another version // and C++ hiding rules would make the base version of this hidden. return base_type::erase(position); } template inline typename set::iterator set::erase(iterator first, iterator last) { // We need to provide this version because we override another version // and C++ hiding rules would make the base version of this hidden. return base_type::erase(first, last); } template inline typename set::size_type set::count(const Key& k) const { const const_iterator it(find(k)); return (it != end()) ? (size_type)1 : (size_type)0; } template inline typename set::reverse_iterator set::erase(reverse_iterator position) { return reverse_iterator(erase((++position).base())); } template inline typename set::reverse_iterator set::erase(reverse_iterator first, reverse_iterator last) { // Version which erases in order from first to last. // difference_type i(first.base() - last.base()); // while(i--) // first = erase(first); // return first; // Version which erases in order from last to first, but is slightly more efficient: return reverse_iterator(erase((++last).base(), (++first).base())); } template inline eastl::pair::iterator, typename set::iterator> set::equal_range(const Key& k) { // The resulting range will either be empty or have one element, // so instead of doing two tree searches (one for lower_bound and // one for upper_bound), we do just lower_bound and see if the // result is a range of size zero or one. const iterator itLower(lower_bound(k)); if((itLower == end()) || mCompare(k, *itLower)) // If at the end or if (k is < itLower)... return eastl::pair(itLower, itLower); iterator itUpper(itLower); return eastl::pair(itLower, ++itUpper); } template inline eastl::pair::const_iterator, typename set::const_iterator> set::equal_range(const Key& k) const { // See equal_range above for comments. const const_iterator itLower(lower_bound(k)); if((itLower == end()) || mCompare(k, *itLower)) // If at the end or if (k is < itLower)... return eastl::pair(itLower, itLower); const_iterator itUpper(itLower); return eastl::pair(itLower, ++itUpper); } /////////////////////////////////////////////////////////////////////// // multiset /////////////////////////////////////////////////////////////////////// template inline multiset::multiset(const allocator_type& allocator) : base_type(allocator) { // Empty } template inline multiset::multiset(const Compare& compare, const allocator_type& allocator) : base_type(compare, allocator) { // Empty } template inline multiset::multiset(const this_type& x) : base_type(x) { // Empty } template template inline multiset::multiset(Iterator itBegin, Iterator itEnd) : base_type(itBegin, itEnd, Compare(), EASTL_MULTISET_DEFAULT_ALLOCATOR) { // Empty } template inline typename multiset::size_type multiset::erase(const Key& k) { const eastl::pair range(equal_range(k)); const size_type n = (size_type)eastl::distance(range.first, range.second); base_type::erase(range.first, range.second); return n; } template inline typename multiset::iterator multiset::erase(iterator position) { // We need to provide this version because we override another version // and C++ hiding rules would make the base version of this hidden. return base_type::erase(position); } template inline typename multiset::iterator multiset::erase(iterator first, iterator last) { // We need to provide this version because we override another version // and C++ hiding rules would make the base version of this hidden. return base_type::erase(first, last); } template inline typename multiset::size_type multiset::count(const Key& k) const { const eastl::pair range(equal_range(k)); return (size_type)eastl::distance(range.first, range.second); } template inline typename multiset::reverse_iterator multiset::erase(reverse_iterator position) { return reverse_iterator(erase((++position).base())); } template inline typename multiset::reverse_iterator multiset::erase(reverse_iterator first, reverse_iterator last) { // Version which erases in order from first to last. // difference_type i(first.base() - last.base()); // while(i--) // first = erase(first); // return first; // Version which erases in order from last to first, but is slightly more efficient: return reverse_iterator(erase((++last).base(), (++first).base())); } template inline eastl::pair::iterator, typename multiset::iterator> multiset::equal_range(const Key& k) { // There are multiple ways to implement equal_range. The implementation mentioned // in the C++ standard and which is used by most (all?) commercial STL implementations // is this: // return eastl::pair(lower_bound(k), upper_bound(k)); // // This does two tree searches -- one for the lower bound and one for the // upper bound. This works well for the case whereby you have a large container // and there are lots of duplicated values. We provide an alternative version // of equal_range called equal_range_small for cases where the user is confident // that the number of duplicated items is only a few. return eastl::pair(lower_bound(k), upper_bound(k)); } template inline eastl::pair::const_iterator, typename multiset::const_iterator> multiset::equal_range(const Key& k) const { // See comments above in the non-const version of equal_range. return eastl::pair(lower_bound(k), upper_bound(k)); } template inline eastl::pair::iterator, typename multiset::iterator> multiset::equal_range_small(const Key& k) { // We provide alternative version of equal_range here which works faster // for the case where there are at most small number of potential duplicated keys. const iterator itLower(lower_bound(k)); iterator itUpper(itLower); while((itUpper != end()) && !mCompare(k, itUpper.mpNode->mValue)) ++itUpper; return eastl::pair(itLower, itUpper); } template inline eastl::pair::const_iterator, typename multiset::const_iterator> multiset::equal_range_small(const Key& k) const { // We provide alternative version of equal_range here which works faster // for the case where there are at most small number of potential duplicated keys. const const_iterator itLower(lower_bound(k)); const_iterator itUpper(itLower); while((itUpper != end()) && !mCompare(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); } } // namespace eastl #endif // Header include guard