// @topic T070m11d07x20 class DString -- copy constructor, destructor, assignment op
// @brief class DString implementation

// DString.cpp
#include "DString.h"

// destructor deallocates previously allocated characters
DString::~DString()
{
    delete[] m_array;
}//DString::~DString


// overloaded assignment op implements a "deep" assignment
DString const& DString::operator=(DString const& another)
{
    if ( this == &another ) {
        // protect against self-assigment
        return *this;
    }
    delete[] m_array;
    m_array = nullptr;

    m_length = another.m_length;
    m_capacity = INITIAL_CAPACITY;

    allocate(another.m_capacity);
    strcpy(m_array, another.m_array);
    return *this;
}//DString::operator=


// copy constructor implements "deep" copy
DString::DString(DString const& another)
    :
    m_array( nullptr ),
    m_length( another.m_length ),
    m_capacity( INITIAL_CAPACITY )
{
    allocate( another.m_capacity );
    strcpy( m_array, another.m_array );
}//DString::DString


// default constructor
DString::DString()
    :
    m_array( nullptr ),
    m_length( 0 ),
    m_capacity( INITIAL_CAPACITY )
{
    allocate( INITIAL_CAPACITY );
}//DString::DString


// specific constructor
DString::DString( char const* pstr )
    :
    m_array( nullptr ),
    m_length( strlen( pstr ) ),
    m_capacity( INITIAL_CAPACITY )
{
    allocate( m_length + 1 ); // +1 needed to accommodate zero-terminating char
    strcpy( m_array, pstr );
}//DString::DString


// allocate black of characters of the requered capacity
void DString::allocate( size_t capacity )
{
    if ( capacity < m_capacity ) return;

    char* new_block = new char[ capacity ];

    if ( m_array != nullptr ) {
        // copy existing content to the new block:
        for ( size_t idx = 0; idx < m_length; ++idx ) {
            new_block[idx] = m_array[idx];
        }
        delete[] m_array; // free old block of characters
    }
    m_array = new_block; // remember new block of characters
    m_capacity = capacity;

}//DString::allocate


size_t DString::length() const
{
    return m_length;
}//DString::length


size_t DString::capacity() const
{
    return m_capacity;
}//DString::capacity


std::ostream& operator<<( std::ostream& cout, DString const& str )
{
    for (size_t idx = 0; idx < str.length(); ++idx ) {
        cout << str.m_array[idx];
    }
    return cout;
}//::operator<<


// extract characters from input stream and
// store them in the dynamic string
std::istream& operator>>( std::istream& cin, DString& str )
{
    str.m_length = 0;
    while ( cin ) {
        int ch = cin.get(); // extract next character form cin
        if ( ch == '\n' ) break; // new line signals end of input

        // before storing next character, check current capacity.
        // provide enough space for the ch and zero-terminating char
        if ( str.m_length >= str.m_capacity - 1 ) {
            // each time the capacity doubles
            str.allocate( str.m_capacity * 2 );
        }
        str.m_array[ str.m_length ] = ch; // store the character
        ++str.m_length;
    }

    str.m_array[str.m_length] = '\x00'; // make sure the content is zero-terminated
    return cin;
}//::operator>>