diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 5ebe697098..ce731070f3 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -28,6 +28,7 @@ lineStream.h lineStreamBuf.I lineStreamBuf.h \ modifierButtons.I modifierButtons.h mouseButton.h \ mouseData.h nameUniquifier.I nameUniquifier.h \ + ordered_vector.h ordered_vector.I ordered_vector.T \ pta_double.h \ pta_float.h pta_int.h \ string_utils.I string_utils.N string_utils.h \ @@ -48,7 +49,9 @@ ioPtaDatagramInt.cxx ioPtaDatagramShort.cxx \ keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \ modifierButtons.cxx mouseButton.cxx mouseData.cxx \ - nameUniquifier.cxx pta_double.cxx pta_float.cxx \ + nameUniquifier.cxx \ + ordered_vector.cxx \ + pta_double.cxx pta_float.cxx \ pta_int.cxx pta_ushort.cxx \ string_utils.cxx timedCycle.cxx typedWritable.cxx \ typedWritableReferenceCount.cxx updateSeq.cxx \ @@ -75,7 +78,9 @@ ioPtaDatagramShort.h iterator_types.h keyboardButton.h lineStream.I \ lineStream.h lineStreamBuf.I lineStreamBuf.h modifierButtons.I \ modifierButtons.h mouseButton.h mouseData.h nameUniquifier.I \ - nameUniquifier.h pta_double.h \ + nameUniquifier.h \ + ordered_vector.h ordered_vector.I ordered_vector.T \ + pta_double.h \ pta_float.h pta_int.h pta_ushort.h string_utils.I \ string_utils.h timedCycle.I timedCycle.h typedWritable.I \ typedWritable.h typedWritableReferenceCount.I \ @@ -134,3 +139,14 @@ test_linestream.cxx #end test_bin_target + +#begin test_bin_target + #define TARGET test_ordered_vector + + #define SOURCES \ + test_ordered_vector.cxx + + #define LOCAL_LIBS $[LOCAL_LIBS] putil + #define OTHER_LIBS $[OTHER_LIBS] pystub + +#end test_bin_target diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 80c2275add..cc02cc8674 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -71,6 +71,8 @@ ConfigureFn(config_util) { //const bool track_memory_usage = config_util.GetBool("track-memory-usage", false); +const bool paranoid_ordered_vector = config_util.GetBool("paranoid-ordered-vector", false); + DSearchPath & get_model_path() { static DSearchPath *model_path = NULL; diff --git a/panda/src/putil/config_util.h b/panda/src/putil/config_util.h index 9a76aeb499..a70d8b7eca 100644 --- a/panda/src/putil/config_util.h +++ b/panda/src/putil/config_util.h @@ -36,6 +36,8 @@ NotifyCategoryDecl(bam, EXPCL_PANDA, EXPTP_PANDA); //extern EXPCL_PANDA const bool track_memory_usage; +extern EXPCL_PANDA const bool paranoid_ordered_vector; + // These are functions instead of constant variables because they are // computed based on the concatenation of all appearances of the // corresponding variable in the config files. diff --git a/panda/src/putil/ordered_vector.I b/panda/src/putil/ordered_vector.I new file mode 100644 index 0000000000..ae95a7422c --- /dev/null +++ b/panda/src/putil/ordered_vector.I @@ -0,0 +1,594 @@ +// Filename: ordered_vector.I +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector:: +ordered_vector(const Compare &compare) : + _compare(compare) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector:: +ordered_vector(const ordered_vector ©) : + _compare(copy._compare), + _vector(copy._vector) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::Copy Assignment Operator +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector &ordered_vector:: +operator = (const ordered_vector ©) { + _compare = copy._compare; + _vector = copy._vector; + return *this; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector:: +~ordered_vector() { +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::begin +// Access: Public +// Description: Returns the iterator that marks the first element in +// the ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +begin() { + return _vector.begin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::end +// Access: Public +// Description: Returns the iterator that marks the end of the +// ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +end() { + return _vector.end(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::rbegin +// Access: Public +// Description: Returns the iterator that marks the first element in +// the ordered vector, when viewed in reverse order. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::reverse_iterator ordered_vector:: +rbegin() { + return _vector.rbegin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::rend +// Access: Public +// Description: Returns the iterator that marks the end of the +// ordered vector, when viewed in reverse order. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::reverse_iterator ordered_vector:: +rend() { + return _vector.rend(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::begin +// Access: Public +// Description: Returns the iterator that marks the first element in +// the ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_iterator ordered_vector:: +begin() const { + return _vector.begin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::end +// Access: Public +// Description: Returns the iterator that marks the end of the +// ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_iterator ordered_vector:: +end() const { + return _vector.end(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::rbegin +// Access: Public +// Description: Returns the iterator that marks the first element in +// the ordered vector, when viewed in reverse order. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_reverse_iterator ordered_vector:: +rbegin() const { + return _vector.rbegin(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::rend +// Access: Public +// Description: Returns the iterator that marks the end of the +// ordered vector, when viewed in reverse order. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_reverse_iterator ordered_vector:: +rend() const { + return _vector.rend(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::size +// Access: Public +// Description: Returns the number of elements in the ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::size_type ordered_vector:: +size() const { + return _vector.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::max_size +// Access: Public +// Description: Returns the maximum number of elements that can +// possibly be stored in an ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::size_type ordered_vector:: +max_size() const { + return _vector.max_size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::empty +// Access: Public +// Description: Returns true if the ordered vector is empty, false +// otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +empty() const { + return _vector.max_size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::operator == +// Access: Public +// Description: Returns true if the two ordered vectors are +// memberwise equivalent, false otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +operator == (const ordered_vector &other) const { + return _vector == other._vector; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::operator != +// Access: Public +// Description: Returns true if the two ordered vectors are not +// memberwise equivalent, false if they are. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +operator != (const ordered_vector &other) const { + return _vector != other._vector; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::operator < +// Access: Public +// Description: Returns true if this ordered vector sorts +// lexicographically before the other one, false +// otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +operator < (const ordered_vector &other) const { + return _vector < other._vector; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::operator > +// Access: Public +// Description: Returns true if this ordered vector sorts +// lexicographically after the other one, false +// otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +operator > (const ordered_vector &other) const { + return _vector > other._vector; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::operator <= +// Access: Public +// Description: Returns true if this ordered vector sorts +// lexicographically before the other one or is +// equivalent, false otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +operator <= (const ordered_vector &other) const { + return _vector <= other._vector; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::operator >= +// Access: Public +// Description: Returns true if this ordered vector sorts +// lexicographically after the other one or is +// equivalent, false otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +operator >= (const ordered_vector &other) const { + return _vector >= other._vector; +} + + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::insert +// Access: Public +// Description: Inserts the indicated key into the ordered vector, at +// the appropriate place. If there are already elements +// sorting equivalent to the key in the vector, the new +// value is inserted following them. The return value +// is the iterator referencing the new element. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +insert(const ordered_vector::value_type &key) { + iterator position = find_insert_position(begin(), end(), key); + nassertr(position >= begin() && position <= end(), end()); + + iterator result = _vector.insert(position, key); + verify_list(); + return result; +} + + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::erase, with iterator +// Access: Public +// Description: Removes the element indicated by the given iterator, +// and returns the next sequential iterator. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +erase(ordered_vector::iterator position) { + size_type count = position - begin(); + _vector.erase(position); + return begin() + count; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::erase, with key +// Access: Public +// Description: Removes all elements matching the indicated key; +// returns the number of elements removed. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::size_type ordered_vector:: +erase(const ordered_vector::key_type &key) { + pair result = equal_range(key); + size_type count = result.second - result.first; + erase(result.first, result.second); + return count; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::erase, a range +// Access: Public +// Description: Removes all elements indicated by the given iterator +// range. +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +erase(ordered_vector::iterator first, + ordered_vector::iterator last) { + _vector.erase(first, last); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::clear +// Access: Public +// Description: Removes all elements from the ordered vector. +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +clear() { + _vector.erase(_vector.begin(), _vector.end()); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::find +// Access: Public +// Description: Searches for an element with the indicated key and +// returns its iterator if it is found, or end() if it +// is not. If there are multiple elements matching the +// key, the particular iterator returned is not defined. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +find(const ordered_vector::key_type &key) { + return (iterator)r_find(begin(), end(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::find +// Access: Public +// Description: Searches for an element with the indicated key and +// returns its iterator if it is found, or end() if it +// is not. If there are multiple elements matching the +// key, the particular iterator returned is not defined. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_iterator ordered_vector:: +find(const ordered_vector::key_type &key) const { + return r_find(begin(), end(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::find_particular +// Access: Public +// Description: Searches for a particular element and returns its +// iterator if it is found, or end() if it is not. +// +// First, the Compare function is used to narrow down +// the range of elements the element might be located +// within; then the element is compared elementwise, via +// ==, until the exact matching element is found. If +// multiple matches exist within the vector, the +// particular iterator returned is not defined. +// +// The assumption is that == implies !Compare(a, b) and +// !Compare(b, a), but not necessarily the converse. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +find_particular(const ordered_vector::key_type &key) { + return (iterator)r_find_particular(begin(), end(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::find_particular +// Access: Public +// Description: Searches for a particular element and returns its +// iterator if it is found, or end() if it is not. +// +// First, the Compare function is used to narrow down +// the range of elements the element might be located +// within; then the element is compared elementwise, via +// ==, until the exact matching element is found. If +// multiple matches exist within the vector, the +// particular iterator returned is not defined./ +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_iterator ordered_vector:: +find_particular(const ordered_vector::key_type &key) const { + return r_find_particular(begin(), end(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::count +// Access: Public +// Description: Returns the number of elements that sort equivalent +// to the key that are in the vector. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::size_type ordered_vector:: +count(const key_type &key) const { + return r_count(begin(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::lower_bound +// Access: Public +// Description: Returns the iterator for the first element not less +// than key, or end() if all elements are less than key. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +lower_bound(const ordered_vector::key_type &key) { + return (iterator)r_lower_bound(begin(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::lower_bound +// Access: Public +// Description: Returns the iterator for the first element not less +// than key, or end() if all elements are less than key. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_iterator ordered_vector:: +lower_bound(const ordered_vector::key_type &key) const { + return r_lower_bound(begin(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::upper_bound +// Access: Public +// Description: Returns the iterator for the first element greater +// than key, or end() if no element is greater than +// key. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +upper_bound(const ordered_vector::key_type &key) { + return (iterator)r_upper_bound(begin(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::upper_bound +// Access: Public +// Description: Returns the iterator for the first element greater +// than key, or end() if no element is greater than +// key. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::const_iterator ordered_vector:: +upper_bound(const ordered_vector::key_type &key) const { + return r_upper_bound(begin(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::equal_range +// Access: Public +// Description: Returns the pair (lower_bound(key), upper_bound(key)). +//////////////////////////////////////////////////////////////////// +template +INLINE pair::iterator, ordered_vector::iterator> ordered_vector:: +equal_range(const ordered_vector::key_type &key) { + pair::const_iterator, ordered_vector::const_iterator> result; + result = r_equal_range(begin(), end(), key); + return pair::iterator, ordered_vector::iterator>((iterator)result.first, (iterator)result.second); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::equal_range +// Access: Public +// Description: Returns the pair (lower_bound(key), upper_bound(key)). +//////////////////////////////////////////////////////////////////// +template +INLINE pair::const_iterator, ordered_vector::const_iterator> ordered_vector:: +equal_range(const ordered_vector::key_type &key) const { + return r_equal_range(begin(), end(), key); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::swap +// Access: Public +// Description: Exchanges the contents of this vector and the other +// vector, in constant time (e.g., with a pointer swap). +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +swap(ordered_vector ©) { + _vector.swap(copy._vector); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::reserve +// Access: Public +// Description: Informs the vector of a planned change in size; +// ensures that the capacity of the vector is greater +// than or equal to n. +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +reserve(ordered_vector::size_type n) { + _vector.reserve(n); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::sort +// Access: Public +// Description: Ensures that the vector is properly sorted after a +// potentially damaging operation. This should not +// normally need to be called, unless the user has +// written to the vector using the non-const iterators. +//////////////////////////////////////////////////////////////////// +template +INLINE void ordered_vector:: +sort() { + ::sort(begin(), end(), _compare); +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::find_insert_position +// Access: Private +// Description: Searches for the appropriate place in the ordered +// vector to insert the indicated key, and returns the +// corresponding iterator. +//////////////////////////////////////////////////////////////////// +template +INLINE ordered_vector::iterator ordered_vector:: +find_insert_position(ordered_vector::iterator first, + ordered_vector::iterator last, + const ordered_vector::key_type &key) { + iterator result = r_find_insert_position(first, last, key); + +#ifndef NDEBUG + // Verify the result. + if (paranoid_ordered_vector) { + // If there is a node before the indicated position, this node + // must not precede it lexicograpically. + if (first < result) { + nassertr(!_compare(key, *(result - 1)), result); + } + // If there is a node after the indicated position, it must not + // precede this node lexicographically. + if (result < last) { + nassertr(!_compare(*(result), key), result); + } + } +#endif + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::verify_list +// Access: Private +// Description: Ensures that the indicated range of elements is +// sorted correctly, if paranoid_ordered_vector is set. +// Generates an assertion failure (and returns false) if +// this is not the case; otherwise, returns true. +//////////////////////////////////////////////////////////////////// +template +INLINE bool ordered_vector:: +verify_list() { +#ifndef NDEBUG + if (paranoid_ordered_vector) { + return verify_list_impl(begin(), end()); + } +#endif + return true; +} diff --git a/panda/src/putil/ordered_vector.T b/panda/src/putil/ordered_vector.T new file mode 100644 index 0000000000..d96c2c28b4 --- /dev/null +++ b/panda/src/putil/ordered_vector.T @@ -0,0 +1,331 @@ +// Filename: ordered_vector.T +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::insert +// Access: Public +// Description: Inserts the indicated key into the ordered vector. +// The iterator is a hint to the expected position; if +// this is correct, the insert operation is likely to be +// faster. The return value is the iterator referencing +// the new element. +//////////////////////////////////////////////////////////////////// +template +ordered_vector::iterator ordered_vector:: +insert(ordered_vector::iterator position, + const ordered_vector::value_type &key) { + if (position != begin()) { + // If we're not inserting at the beginning, this element should + // not lexicographically precede the one we're inserting after. + if (_compare(key, *(position - 1))) { + return insert(key); + } + } + + if (position != end()) { + // If we're not inserting at the beginning, the element we're + // inserting before should not lexicographically precede this one. + if (_compare(*position, key)) { + return insert(key); + } + } + + // Otherwise, we may insert where the caller requested. + iterator result = _vector.insert(position, key); + verify_list(); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_find_insert_position +// Access: Private +// Description: The recursive implementation of +// find_insert_position(). +//////////////////////////////////////////////////////////////////// +template +ordered_vector::iterator ordered_vector:: +r_find_insert_position(ordered_vector::iterator first, + ordered_vector::iterator last, + const ordered_vector::key_type &key) { + if (first == last) { + // The list is empty; the insert position is the last of the list. + return last; + } + + iterator center = first + (last - first) / 2; + nassertr(center < last, last); + + if (_compare(key, *center)) { + // Insert before the center. + return r_find_insert_position(first, center, key); + + } else { + // Insert after the center. + return r_find_insert_position(center + 1, last, key); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_find +// Access: Private +// Description: The recursive implementation of find(). +//////////////////////////////////////////////////////////////////// +template +ordered_vector::const_iterator ordered_vector:: +r_find(ordered_vector::const_iterator first, + ordered_vector::const_iterator last, + ordered_vector::const_iterator not_found, + const ordered_vector::key_type &key) const { + if (first == last) { + // The list is empty; the key is not on the list. + return not_found; + } + + const_iterator center = first + (last - first) / 2; + nassertr(center < last, last); + + if (_compare(key, *center)) { + // It must be before the center. + return r_find(first, center, not_found, key); + + } else if (_compare(*center, key)) { + // It must be after the center. + return r_find(center + 1, last, not_found, key); + + } else { + // Here it is! + return center; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_find_particular +// Access: Private +// Description: The recursive implementation of find_particular(). +//////////////////////////////////////////////////////////////////// +template +ordered_vector::const_iterator ordered_vector:: +r_find_particular(ordered_vector::const_iterator first, + ordered_vector::const_iterator last, + ordered_vector::const_iterator not_found, + const ordered_vector::key_type &key) const { + if (first == last) { + // The list is empty; the key is not on the list. + return not_found; + } + + const_iterator center = first + (last - first) / 2; + nassertr(center < last, last); + + if (_compare(key, *center)) { + // It must be before the center. + return r_find_particular(first, center, not_found, key); + + } else if (_compare(*center, key)) { + // It must be after the center. + return r_find_particular(center + 1, last, not_found, key); + + } else { + // The center's sort matches the key's sort. It could be either + // before or after the center. First try after. + const_iterator i = center; + while (i < last && !_compare(key, *i)) { + if ((*i) == key) { + return i; + } + ++i; + } + + // No, try before. + i = center; + --i; + while (i >= first && !_compare(key, *i)) { + if ((*i) == key) { + return i; + } + --i; + } + + // No such key! + return not_found; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_count +// Access: Private +// Description: The recursive implementation of count(). +//////////////////////////////////////////////////////////////////// +template +ordered_vector::size_type ordered_vector:: +r_count(ordered_vector::const_iterator first, + ordered_vector::const_iterator last, + const ordered_vector::key_type &key) const { + typedef pair::const_iterator, ordered_vector::const_iterator> pair_type; + + if (first == last) { + // The list is empty; the key is not on the list. + return 0; + } + + const_iterator center = first + (last - first) / 2; + nassertr(center < last, 0); + + if (_compare(key, *center)) { + // It must be before the center. + return r_count(first, center, key); + + } else if (_compare(*center, key)) { + // It must be after the center. + return r_count(center + 1, last, key); + + } else { + // The center matches the key; the range is here. + size_type lower = r_count(first, center, key); + size_type upper = r_count(center + 1, last, key); + return lower + 1 + upper; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_lower_bound +// Access: Private +// Description: The recursive implementation of lower_bound(). +//////////////////////////////////////////////////////////////////// +template +ordered_vector::const_iterator ordered_vector:: +r_lower_bound(ordered_vector::const_iterator first, + ordered_vector::const_iterator last, + const ordered_vector::key_type &key) const { + if (first == last) { + // The list is empty; the key is not on the list. + return last; + } + + const_iterator center = first + (last - first) / 2; + nassertr(center < last, last); + + if (_compare(key, *center)) { + // It must be before the center. + return r_lower_bound(first, center, key); + + } else if (_compare(*center, key)) { + // It must be after the center. + return r_lower_bound(center + 1, last, key); + + } else { + // The center matches the key; thus, the first element not less + // than key is at or before the center. + return r_lower_bound(first, center, key); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_upper_bound +// Access: Private +// Description: The recursive implementation of upper_bound(). +//////////////////////////////////////////////////////////////////// +template +ordered_vector::const_iterator ordered_vector:: +r_upper_bound(ordered_vector::const_iterator first, + ordered_vector::const_iterator last, + const ordered_vector::key_type &key) const { + if (first == last) { + // The list is empty; the key is not on the list. + return last; + } + + const_iterator center = first + (last - first) / 2; + nassertr(center < last, last); + + if (_compare(key, *center)) { + // It must be before the center. + return r_upper_bound(first, center, key); + + } else if (_compare(*center, key)) { + // It must be after the center. + return r_upper_bound(center + 1, last, key); + + } else { + // The center matches the key; thus, the first element greater + // than key is after the center. + return r_upper_bound(center + 1, last, key); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_equal_range +// Access: Private +// Description: The recursive implementation of equal_range(). +//////////////////////////////////////////////////////////////////// +template +pair::const_iterator, ordered_vector::const_iterator> ordered_vector:: +r_equal_range(ordered_vector::const_iterator first, + ordered_vector::const_iterator last, + const ordered_vector::key_type &key) const { + typedef pair::const_iterator, ordered_vector::const_iterator> pair_type; + + if (first == last) { + // The list is empty; the key is not on the list. + return pair_type(last, last); + } + + const_iterator center = first + (last - first) / 2; + nassertr(center < last, pair_type(last, last)); + + if (_compare(key, *center)) { + // It must be before the center. + return r_equal_range(first, center, key); + + } else if (_compare(*center, key)) { + // It must be after the center. + return r_equal_range(center + 1, last, key); + + } else { + // The center matches the key; the range is here. + const_iterator lower = r_lower_bound(first, center, key); + const_iterator upper = r_upper_bound(center + 1, last, key); + return pair_type(lower, upper); + } +} + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::verify_list_impl +// Access: Private +// Description: The non-inline implementation of verify_list(). +//////////////////////////////////////////////////////////////////// +template +bool ordered_vector:: +verify_list_impl(ordered_vector::iterator first, + ordered_vector::iterator last) { + if (first < last) { + iterator prev = first; + iterator i = first; + ++i; + while (i < last) { + bool ordered_correctly = !_compare(*i, *prev); + nassertr(ordered_correctly, false); + prev = i; + ++i; + } + } + return true; +} +#endif // NDEBUG diff --git a/panda/src/putil/ordered_vector.cxx b/panda/src/putil/ordered_vector.cxx new file mode 100644 index 0000000000..bb11d9ef4c --- /dev/null +++ b/panda/src/putil/ordered_vector.cxx @@ -0,0 +1,19 @@ +// Filename: ordered_vector.cxx +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "ordered_vector.h" diff --git a/panda/src/putil/ordered_vector.h b/panda/src/putil/ordered_vector.h new file mode 100644 index 0000000000..ed895b7aa9 --- /dev/null +++ b/panda/src/putil/ordered_vector.h @@ -0,0 +1,160 @@ +// Filename: ordered_vector.h +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef ORDERED_VECTOR_H +#define ORDERED_VECTOR_H + +#include "pandabase.h" +#include "config_util.h" + +#include "pvector.h" +#include "pset.h" +#include + +//////////////////////////////////////////////////////////////////// +// Class : ordered_vector +// Description : This template class presents an interface similar to +// the STL multiset, but it is implemented using a vector +// that is kept always in sorted order. +// +// This allows the ordered_vector to maintain stability +// of order between elements that sort equally: they are +// stored in the order in which they were added, from +// back to front. +//////////////////////////////////////////////////////////////////// +template > +class ordered_vector { +private: + typedef pvector Vector; + +public: + // Typedefs + typedef Key key_type; + typedef Key value_type; + typedef Key &reference; + typedef const Key &const_reference; + typedef Compare key_compare; + typedef Compare value_compare; + + // Be careful when using the non-const iterators that you do not + // disturb the sorted order of the vector, or that if you do, you + // call sort() when you are done. + typedef Vector::iterator iterator; + typedef Vector::const_iterator const_iterator; + typedef Vector::reverse_iterator reverse_iterator; + typedef Vector::const_reverse_iterator const_reverse_iterator; + + typedef Vector::difference_type difference_type; + typedef Vector::size_type size_type; + +public: + // Constructors. We don't implement the whole slew of STL + // constructors here yet. + INLINE ordered_vector(const Compare &compare = Compare()); + INLINE ordered_vector(const ordered_vector ©); + INLINE ordered_vector &operator = (const ordered_vector ©); + INLINE ~ordered_vector(); + + // Iterator access. + INLINE iterator begin(); + INLINE iterator end(); + INLINE reverse_iterator rbegin(); + INLINE reverse_iterator rend(); + + INLINE const_iterator begin() const; + INLINE const_iterator end() const; + INLINE const_reverse_iterator rbegin() const; + INLINE const_reverse_iterator rend() const; + + // Size information. + INLINE size_type size() const; + INLINE size_type max_size() const; + INLINE bool empty() const; + + // Equivalence and lexicographical comparisons. + INLINE bool operator == (const ordered_vector &other) const; + INLINE bool operator != (const ordered_vector &other) const; + + INLINE bool operator < (const ordered_vector &other) const; + INLINE bool operator > (const ordered_vector &other) const; + INLINE bool operator <= (const ordered_vector &other) const; + INLINE bool operator >= (const ordered_vector &other) const; + + // Insert operations. + iterator insert(iterator position, const value_type &key); + INLINE iterator insert(const value_type &key); + + // Erase operations. + INLINE iterator erase(iterator position); + INLINE size_type erase(const key_type &key); + INLINE void erase(iterator first, iterator last); + INLINE void clear(); + + // Find operations. + INLINE iterator find(const key_type &key); + INLINE const_iterator find(const key_type &key) const; + INLINE iterator find_particular(const key_type &key); + INLINE const_iterator find_particular(const key_type &key) const; + INLINE size_type count(const key_type &key) const; + + INLINE iterator lower_bound(const key_type &key); + INLINE const_iterator lower_bound(const key_type &key) const; + INLINE iterator upper_bound(const key_type &key); + INLINE const_iterator upper_bound(const key_type &key) const; + INLINE pair equal_range(const key_type &key); + INLINE pair equal_range(const key_type &key) const; + + // Special operations. + INLINE void swap(ordered_vector &other); + INLINE void reserve(size_type n); + INLINE void sort(); + +private: + INLINE iterator find_insert_position(iterator first, iterator last, + const key_type &key); + iterator r_find_insert_position(iterator first, iterator last, + const key_type &key); + const_iterator r_find(const_iterator first, const_iterator last, + const_iterator not_found, + const key_type &key) const; + const_iterator r_find_particular(const_iterator first, const_iterator last, + const_iterator not_found, + const key_type &key) const; + size_type r_count(const_iterator first, const_iterator last, + const key_type &key) const; + const_iterator r_lower_bound(const_iterator first, const_iterator last, + const key_type &key) const; + const_iterator r_upper_bound(const_iterator first, const_iterator last, + const key_type &key) const; + pair + r_equal_range(const_iterator first, const_iterator last, + const key_type &key) const; + INLINE bool verify_list(); + +#ifndef NDEBUG + bool verify_list_impl(iterator first, iterator last); +#endif + + Compare _compare; + Vector _vector; +}; + +#include "ordered_vector.I" +#include "ordered_vector.T" + +#endif diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index fd22e74715..24e5b24d73 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -1,5 +1,6 @@ #include "nameUniquifier.cxx" +#include "ordered_vector.cxx" #include "pta_double.cxx" #include "pta_float.cxx" #include "pta_int.cxx" diff --git a/panda/src/putil/test_ordered_vector.cxx b/panda/src/putil/test_ordered_vector.cxx new file mode 100644 index 0000000000..761c363b07 --- /dev/null +++ b/panda/src/putil/test_ordered_vector.cxx @@ -0,0 +1,84 @@ +// Filename: test_ordered_vector.cxx +// Created by: drose (20Feb02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "ordered_vector.h" + +typedef ordered_vector myvec; + +void +search(myvec &v, int element) { + pair result; + + result = v.equal_range(element); + size_t count = v.count(element); + + cerr << element << " bounded by " << result.first - v.begin() << " and " + << result.second - v.begin() << "; " << count << " total.\n"; +} + +int +main(int argc, char *argv[]) { + myvec a, b; + + myvec::iterator mi; + mi = a.insert(a.end(), 3); + mi = a.insert(mi, 5); + mi = a.insert(mi, 4); + mi = a.insert(mi, 4); + mi = a.insert(mi, 2); + mi = a.insert(mi, 5); + mi = a.insert(mi, 2); + + a.swap(b); + + cerr << b.size() << " elements:\n"; + + myvec::iterator bi; + for (bi = b.begin(); bi != b.end(); ++bi) { + cerr << *bi << " "; + } + cerr << "\n"; + + search(b, 1); + search(b, 2); + search(b, 3); + search(b, 4); + search(b, 5); + search(b, 6); + + cerr << "Removing 4:\n"; + size_t count = b.erase(4); + cerr << "Removed " << count << "\n"; + + + cerr << b.size() << " elements:\n"; + + for (bi = b.begin(); bi != b.end(); ++bi) { + cerr << *bi << " "; + } + cerr << "\n"; + + search(b, 1); + search(b, 2); + search(b, 3); + search(b, 4); + search(b, 5); + search(b, 6); + + return (0); +}