diff --git a/dtool/src/dtoolbase/pallocator.T b/dtool/src/dtoolbase/pallocator.T index aa2396d437..f7c18b2792 100644 --- a/dtool/src/dtoolbase/pallocator.T +++ b/dtool/src/dtoolbase/pallocator.T @@ -3,3 +3,72 @@ // //////////////////////////////////////////////////////////////////// // +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +template +INLINE pallocator_single:: +pallocator_single(TypeHandle type_handle) throw() : + _type_handle(type_handle) +{ +} + +template +INLINE TYPENAME pallocator_single::pointer pallocator_single:: +allocate(TYPENAME pallocator_single::size_type n, TYPENAME allocator::const_pointer) { + TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER); + // This doesn't support allocating arrays. + assert(n == 1); + return StaticDeletedChain::allocate(sizeof(Type), _type_handle); +} + +template +INLINE void pallocator_single:: +deallocate(TYPENAME pallocator_single::pointer p, TYPENAME pallocator_single::size_type) { + TAU_PROFILE("pallocator_single:deallocate()", " ", TAU_USER); + StaticDeletedChain::deallocate(p, _type_handle); +} + +template +INLINE pallocator_array:: +pallocator_array(TypeHandle type_handle) throw() : + _type_handle(type_handle) +{ +} + +template +INLINE TYPENAME pallocator_array::pointer pallocator_array:: +allocate(TYPENAME pallocator_array::size_type n, TYPENAME allocator::const_pointer) { + TAU_PROFILE("pallocator_array:allocate()", " ", TAU_USER); +#ifdef DO_MEMORY_USAGE + size_t alloc_size = n * sizeof(Type); + // We also need to store the total number of bytes we allocated. + alloc_size += sizeof(size_t); + _type_handle.inc_memory_usage(TypeHandle::MC_array, (int)alloc_size); + void *ptr = (TYPENAME pallocator_array::pointer)PANDA_MALLOC_ARRAY(alloc_size); + *((size_t *)ptr) = alloc_size; + return (TYPENAME pallocator_array::pointer)(((size_t *)ptr) + 1); +#else + return (TYPENAME pallocator_array::pointer)malloc(n * sizeof(Type)); +#endif // DO_MEMORY_USAGE +} + +template +INLINE void pallocator_array:: +deallocate(TYPENAME pallocator_array::pointer p, TYPENAME pallocator_array::size_type) { + TAU_PROFILE("pallocator_array:deallocate()", " ", TAU_USER); +#ifdef DO_MEMORY_USAGE + // Now we need to recover the total number of bytes. + size_t alloc_size = *(((size_t *)p) - 1); + _type_handle.dec_memory_usage(TypeHandle::MC_array, (int)alloc_size); + PANDA_FREE_ARRAY(((size_t *)p) - 1); +#else + free(p); +#endif // DO_MEMORY_USAGE +} diff --git a/panda/src/express/dcast.T b/panda/src/express/dcast.T index 12d835d308..251f278dce 100644 --- a/panda/src/express/dcast.T +++ b/panda/src/express/dcast.T @@ -3,3 +3,100 @@ // //////////////////////////////////////////////////////////////////// // +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: _dcast_get_typehandle +// Description: Returns the TypeHandle associated with the type of +// the parameter, if it can be determined. This is a +// support function for _dcast, below. +//////////////////////////////////////////////////////////////////// +template +INLINE TypeHandle +_dcast_get_typehandle(WantType *) { + TAU_PROFILE("_dcast_get_typehandle()", " ", TAU_USER); + TypeHandle handle = WantType::get_class_type(); + +#ifdef _DEBUG + if (handle == TypeHandle::none()) { + // This type handle is unregistered. Oops! + WantType::init_type(); + handle = WantType::get_class_type(); + express_cat->warning() + << "Type " << handle << " was unregistered!\n"; + } +#endif + + return handle; +} + + +//////////////////////////////////////////////////////////////////// +// Function: _dcast +// Description: The implementation of the DCAST macro, this checks +// the actual type of the pointer before performing a +// downcast operation. In NDEBUG mode, it simply +// downcasts. +// +// This flavor of _dcast works on non-const pointers. +//////////////////////////////////////////////////////////////////// +template +INLINE WantType * +_dcast(WantType *, TypedObject *ptr) { +#ifdef DO_DCAST + TAU_PROFILE("_dcast()", " ", TAU_USER); + TypeHandle want_handle = _dcast_get_typehandle((WantType *)0); + if (!_dcast_verify(want_handle, sizeof(WantType), ptr)) { + return (WantType *)NULL; + } +#endif + return (WantType *)ptr; +} + +//////////////////////////////////////////////////////////////////// +// Function: _dcast +// Description: The implementation of the DCAST macro, this checks +// the actual type of the pointer before performing a +// downcast operation. In NDEBUG mode, it simply +// downcasts. +// +// This flavor of _dcast works on const pointers. +//////////////////////////////////////////////////////////////////// +template +INLINE const WantType * +_dcast(WantType *, const TypedObject *ptr) { +#ifdef DO_DCAST + TAU_PROFILE("_dcast()", " ", TAU_USER); + TypeHandle want_handle = _dcast_get_typehandle((WantType *)0); + if (!_dcast_verify(want_handle, sizeof(WantType), ptr)) { + return (const WantType *)NULL; + } +#endif + return (const WantType *)ptr; +} + +//////////////////////////////////////////////////////////////////// +// Function: _dcast_ref +// Description: Similar to the above, with a pointer reference as the +// first parameter. Just for fiddly compiler reasons; +// the reference isn't used. +//////////////////////////////////////////////////////////////////// +template +INLINE WantType * +_dcast_ref(WantType *&, TypedObject *ptr) { + return _dcast((WantType *)NULL, ptr); +} + +template +INLINE const WantType * +_dcast_ref(WantType *&, const TypedObject *ptr) { + return _dcast((WantType *)NULL, ptr); +} diff --git a/panda/src/express/ordered_vector.T b/panda/src/express/ordered_vector.T index b6aa8e830f..ad0e24b5a5 100644 --- a/panda/src/express/ordered_vector.T +++ b/panda/src/express/ordered_vector.T @@ -3,3 +3,407 @@ // //////////////////////////////////////////////////////////////////// // +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::insert_unique +// 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. +// +// This flavor of insert does not allow multiple copies +// of the same key to be inserted. If the key is +// already present, it is not inserted, and the iterator +// referencing the original value is returned. +//////////////////////////////////////////////////////////////////// +template +TYPENAME ordered_vector::ITERATOR ordered_vector:: +insert_unique(TYPENAME ordered_vector::ITERATOR position, + const TYPENAME ordered_vector::VALUE_TYPE &key) { + TAU_PROFILE("ordered_vector::insert_unique(iterator, const value_type &)", " ", TAU_USER); + if (position != end()) { + // If we're not inserting at the end, the element we're + // inserting before should not lexicographically precede this one. + if (_compare(*position, key)) { + return insert_unique(key).first; + + } else if (!_compare(key, *position)) { + // Oops, !(*position < key) and !(key < *position). That means + // they're equivalent, and we shouldn't insert a new one. + return position; + } + } + + 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_unique(key).first; + + } else if (!_compare(*(position - 1), key)) { + // Once again, they're equivalent. + return position - 1; + } + } + + // Otherwise, we may insert where the caller requested. + ITERATOR result = _vector.insert(position, key); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::insert_nonunique +// 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. +// +// This flavor of insert allows multiple copies of the +// same key to be inserted. +//////////////////////////////////////////////////////////////////// +template +TYPENAME ordered_vector::ITERATOR ordered_vector:: +insert_nonunique(TYPENAME ordered_vector::ITERATOR position, + const TYPENAME ordered_vector::VALUE_TYPE &key) { + TAU_PROFILE("ordered_vector::insert_nonunique(iterator, const value_type &)", " ", TAU_USER); + if (position != end()) { + // If we're not inserting at the end, the element we're + // inserting before should not lexicographically precede this one. + if (_compare(*position, key)) { + return insert_nonunique(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_nonunique(key); + } + } + + // Otherwise, we may insert where the caller requested. + ITERATOR result = _vector.insert(position, key); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::verify_list_unique +// Access: Public +// Description: Ensures that the indicated range of elements is +// sorted correctly. Returns true if this is the case; +// otherwise, returns false. +//////////////////////////////////////////////////////////////////// +template +bool ordered_vector:: +verify_list_unique() const { + TAU_PROFILE("ordered_vector::verify_list_unique()", " ", TAU_USER); + if (!empty()) { + CONST_ITERATOR prev = begin(); + CONST_ITERATOR i = begin(); + ++i; + while (i < end()) { + bool ordered_correctly = _compare(*prev, *i); + if (!ordered_correctly) { + return true; + } + prev = i; + ++i; + } + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::verify_list_nonunique +// Access: Public +// Description: Ensures that the indicated range of elements is +// sorted correctly. Returns true if this is the case; +// otherwise, returns false. +//////////////////////////////////////////////////////////////////// +template +bool ordered_vector:: +verify_list_nonunique() const { + TAU_PROFILE("ordered_vector::verify_list_nonunique()", " ", TAU_USER); + if (!empty()) { + CONST_ITERATOR prev = begin(); + CONST_ITERATOR i = begin(); + ++i; + while (i < end()) { + bool ordered_correctly = !_compare(*i, *prev); + if (!ordered_correctly) { + return true; + } + prev = i; + ++i; + } + } + return true; +} + + +//////////////////////////////////////////////////////////////////// +// Function: ordered_vector::r_find_insert_position +// Access: Private +// Description: The recursive implementation of +// find_insert_position(). +//////////////////////////////////////////////////////////////////// +template +TYPENAME ordered_vector::ITERATOR ordered_vector:: +r_find_insert_position(TYPENAME ordered_vector::ITERATOR first, + TYPENAME ordered_vector::ITERATOR last, + const TYPENAME 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 +TYPENAME ordered_vector::CONST_ITERATOR ordered_vector:: +r_find(TYPENAME ordered_vector::CONST_ITERATOR first, + TYPENAME ordered_vector::CONST_ITERATOR last, + TYPENAME ordered_vector::CONST_ITERATOR not_found, + const TYPENAME 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 +TYPENAME ordered_vector::CONST_ITERATOR ordered_vector:: +r_find_particular(TYPENAME ordered_vector::CONST_ITERATOR first, + TYPENAME ordered_vector::CONST_ITERATOR last, + TYPENAME ordered_vector::CONST_ITERATOR not_found, + const TYPENAME 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 +TYPENAME ordered_vector::SIZE_TYPE ordered_vector:: +r_count(TYPENAME ordered_vector::CONST_ITERATOR first, + TYPENAME ordered_vector::CONST_ITERATOR last, + const TYPENAME ordered_vector::KEY_TYPE &key) const { + typedef pair::CONST_ITERATOR, TYPENAME 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 +TYPENAME ordered_vector::CONST_ITERATOR ordered_vector:: +r_lower_bound(TYPENAME ordered_vector::CONST_ITERATOR first, + TYPENAME ordered_vector::CONST_ITERATOR last, + const TYPENAME 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 +TYPENAME ordered_vector::CONST_ITERATOR ordered_vector:: +r_upper_bound(TYPENAME ordered_vector::CONST_ITERATOR first, + TYPENAME ordered_vector::CONST_ITERATOR last, + const TYPENAME 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, TYPENAME ordered_vector::CONST_ITERATOR> ordered_vector:: +r_equal_range(TYPENAME ordered_vector::CONST_ITERATOR first, + TYPENAME ordered_vector::CONST_ITERATOR last, + const TYPENAME ordered_vector::KEY_TYPE &key) const { + typedef pair::CONST_ITERATOR, TYPENAME 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); + } +}