212 lines
5.3 KiB
C
212 lines
5.3 KiB
C
|
/*
|
||
|
Copyright (C) 2001-2006, William Joseph.
|
||
|
All Rights Reserved.
|
||
|
|
||
|
This file is part of GtkRadiant.
|
||
|
|
||
|
GtkRadiant is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
GtkRadiant 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 General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with GtkRadiant; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#if !defined( INCLUDED_CONTAINER_STACK_H )
|
||
|
#define INCLUDED_CONTAINER_STACK_H
|
||
|
|
||
|
#include "memory/allocator.h"
|
||
|
#include <algorithm>
|
||
|
|
||
|
/// \brief A stack whose storage capacity is variable at run-time. Similar to std::vector.
|
||
|
///
|
||
|
/// - Pushing or popping elements is a constant-time operation (on average).
|
||
|
/// - The storage capacity of the stack will grow when a new element is added beyond the current capacity. Iterators are invalidated when the storage capacity grows.
|
||
|
/// - DefaultConstructible, Copyable, Assignable.
|
||
|
/// - Compatible with the containers and algorithms in the Standard Template Library (STL) - http://www.sgi.com/tech/stl/
|
||
|
///
|
||
|
/// \param Type: The type to be stored in the stack. Must provide a copy-constructor.
|
||
|
template<typename Type>
|
||
|
class Stack : public DefaultAllocator<Type>
|
||
|
{
|
||
|
typedef DefaultAllocator<Type> Allocator;
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
DEFAULT_CAPACITY = 4,
|
||
|
};
|
||
|
|
||
|
typedef Type* pointer;
|
||
|
typedef const Type* const_pointer;
|
||
|
|
||
|
public:
|
||
|
typedef const_pointer const_iterator;
|
||
|
private:
|
||
|
|
||
|
pointer m_data;
|
||
|
pointer m_end;
|
||
|
std::size_t m_capacity;
|
||
|
|
||
|
|
||
|
void insert( const Type& value ){
|
||
|
Allocator::construct( m_end++, value );
|
||
|
}
|
||
|
void insert_overflow( const Type& value ){
|
||
|
const std::size_t new_capacity = ( m_capacity ) ? m_capacity + m_capacity : std::size_t( DEFAULT_CAPACITY );
|
||
|
const pointer new_data = Allocator::allocate( new_capacity );
|
||
|
const pointer new_end = std::copy( m_data, m_end, new_data );
|
||
|
|
||
|
destroy();
|
||
|
Allocator::deallocate( m_data, m_capacity );
|
||
|
|
||
|
m_capacity = new_capacity;
|
||
|
m_data = new_data;
|
||
|
m_end = new_end;
|
||
|
insert( value );
|
||
|
}
|
||
|
void destroy(){
|
||
|
for ( pointer p = m_data; p != m_end; ++p )
|
||
|
{
|
||
|
Allocator::destroy( p );
|
||
|
}
|
||
|
}
|
||
|
void construct( const Stack& other ){
|
||
|
pointer p = m_data;
|
||
|
for ( const_iterator i = other.begin(); i != other.end(); ++i )
|
||
|
{
|
||
|
Allocator::construct( p++, *i );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
|
||
|
Stack() :
|
||
|
m_data( 0 ),
|
||
|
m_end( 0 ),
|
||
|
m_capacity( 0 ){
|
||
|
}
|
||
|
Stack( const Type& value ) :
|
||
|
m_data( 0 ),
|
||
|
m_end( 0 ),
|
||
|
m_capacity( 0 ){
|
||
|
push( value );
|
||
|
}
|
||
|
Stack( const Stack& other ) :
|
||
|
DefaultAllocator<Type>( other ){
|
||
|
m_capacity = other.m_capacity;
|
||
|
m_data = Allocator::allocate( m_capacity );
|
||
|
construct( other );
|
||
|
m_end = m_data + other.size();
|
||
|
}
|
||
|
~Stack(){
|
||
|
destroy();
|
||
|
Allocator::deallocate( m_data, m_capacity );
|
||
|
}
|
||
|
|
||
|
const_iterator begin() const {
|
||
|
return m_data;
|
||
|
}
|
||
|
const_iterator end() const {
|
||
|
return m_end;
|
||
|
}
|
||
|
|
||
|
bool empty() const {
|
||
|
return end() == begin();
|
||
|
}
|
||
|
void clear(){
|
||
|
destroy();
|
||
|
m_end = m_data;
|
||
|
}
|
||
|
|
||
|
std::size_t size() const {
|
||
|
return m_end - m_data;
|
||
|
}
|
||
|
Type operator[]( const std::size_t i ) const {
|
||
|
return m_data[i];
|
||
|
}
|
||
|
/// \brief Pushes \p value onto the stack at the top element. If reserved storage is insufficient for the new element, this will invalidate all iterators.
|
||
|
void push( const Type& value ){
|
||
|
if ( size() == m_capacity ) {
|
||
|
insert_overflow( value );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
insert( value );
|
||
|
}
|
||
|
}
|
||
|
/// \brief Removes the top element of the stack.
|
||
|
void pop(){
|
||
|
Allocator::destroy( --m_end );
|
||
|
}
|
||
|
/// \brief Returns the top element of the mutable stack.
|
||
|
Type& top(){
|
||
|
return *( m_end - 1 );
|
||
|
}
|
||
|
/// \brief Returns the top element of the non-mutable stack.
|
||
|
const Type& top() const {
|
||
|
return *( m_end - 1 );
|
||
|
}
|
||
|
/// \brief Returns the element below the top element of the mutable stack.
|
||
|
Type& parent(){
|
||
|
return *( m_end - 2 );
|
||
|
}
|
||
|
/// \brief Returns the element below the top element of the non-mutable stack.
|
||
|
const Type& parent() const {
|
||
|
return *( m_end - 2 );
|
||
|
}
|
||
|
/// \brief Swaps the values of this stack and \p other.
|
||
|
void swap( Stack& other ){
|
||
|
std::swap( m_data, other.m_data );
|
||
|
std::swap( m_end, other.m_end );
|
||
|
std::swap( m_capacity, other.m_capacity );
|
||
|
}
|
||
|
#if 1 // use copy-swap technique
|
||
|
Stack& operator=( const Stack& other ){
|
||
|
Stack temp( other );
|
||
|
temp.swap( *this );
|
||
|
return *this;
|
||
|
}
|
||
|
#else // avoids memory allocation if capacity is already sufficient.
|
||
|
Stack& operator=( const Stack& other ){
|
||
|
if ( &other != this ) {
|
||
|
destroy();
|
||
|
|
||
|
if ( other.size() > m_capacity ) {
|
||
|
Allocator::deallocate( m_data, m_capacity );
|
||
|
m_capacity = other.m_capacity;
|
||
|
m_data = Allocator::allocate( m_capacity );
|
||
|
}
|
||
|
m_end = m_data + other.size();
|
||
|
|
||
|
construct( other );
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
/// \brief Returns true if \p self is lexicographically less than \p other.
|
||
|
template<typename Type>
|
||
|
inline bool operator<( const Stack<Type>& self, const Stack<Type>& other ){
|
||
|
return std::lexicographical_compare( self.begin(), self.end(), other.begin(), other.end() );
|
||
|
}
|
||
|
|
||
|
namespace std
|
||
|
{
|
||
|
/// \brief Swaps the values of \p self and \p other.
|
||
|
/// Overloads std::swap().
|
||
|
template<typename Type>
|
||
|
inline void swap( Stack<Type>& self, Stack<Type>& other ){
|
||
|
self.swap( other );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|