Wednesday

Software Design Patterns: Adapter pattern using C++

Why?

Convert the interface of a class into another interface clients expect. Adapter lets

classes work together that couldn't otherwise because of incompatible interfaces


Code:

#include <iostream>

#include <string>

#include <cassert>

using namespace std;


class Node

{

    friend void print_list( Node const& head );


public:

    Node* pnext;

    int data;


    // Constructor taking initial value

    Node( int value = 0 );


    // Copy constructor

    Node( Node const& other );


    // Destructor

    ~Node();


    // Insert new node in front

    void insert( Node* newNode );


    // Remove node in front:

    void remove_next();


    // Remove other node in front

    bool remove( Node* other );


    // Measure distance to other node

    int distance( Node const* other ) const;


    // Calculate number of nodes in the list

    size_t size() const;

};



// Constructor taking initial value

Node::Node( int value )

: pnext( nullptr ), data( value )

{

}


// Copy constructor

Node::Node( Node const& other )

: pnext( nullptr ), data( other.data )

{

}


// Destructor

Node::~Node()

{

}


// Insert new node in front

void Node::insert( Node* newNode )

{

    newNode->pnext = pnext;

    pnext = newNode;

}


// Remove node in front

void Node::remove_next()

{

    if ( pnext == nullptr ) return;

    Node* obsolete = pnext;

    this->pnext = obsolete->pnext;

    // Make node "single"

    obsolete->pnext = nullptr;

}


// Remove other node in front

bool Node::remove( Node* other )

{

    Node* previous = this;

    Node* iter = pnext;


    while ( iter != other ) {

       if ( iter == nullptr )

           return false;

       previous = iter;

       iter = iter->pnext;

    }

    previous->pnext = iter->pnext;


    // Make node single after successful removal

    other->pnext = nullptr;


    return true;

}


// Measure distance to other node

int Node::distance( Node const* other ) const

{

    int hops = 1;

    Node const* iter = pnext;

    while ( iter != other ) {

       if ( iter == nullptr ) {

           // Don't count this last hop

           return hops - 1;

       }

       iter = iter->pnext;

       ++hops;

    }

    return hops;

}

// Calculate number of nodes in the list

size_t Node::size() const

{

    return distance( nullptr );

}


// Print contents of the list

void print_list( Node const& head )

{

    cout << '[' << head.size() << "] ";

    Node const* iter = &head;

    do {

       cout << iter->data << ' ';

       iter = iter->pnext;


    } while ( iter != nullptr );

    cout << '\n';

}



class Stack {

    friend void print_stack( Stack const& st );

    Node head;


public:

    // Constructor

    Stack();


    // Destructor

    ~Stack();


    // Push new element to the stack

    void push( int value );


    // Pop element from the stack

    void pop();


    // Writeable access to element on top of the stack

    int& top();


    // Read-only access to element on top of the stack

    int top() const;


    // Return stack size

    size_t size() const;


    // Return true if stack is empty

    bool empty() const;


};


// Constructor

Stack::Stack()

{

}


// Destructor needs to deallocate dynamically allocated nodes

Stack::~Stack()

{

    // Remove all dynamic nodes from the list

    Node* iter = head.pnext;

    while ( iter != nullptr ) {

        Node* obsolete = iter;

        iter = iter->pnext;

        delete obsolete; // remove node from memory

    }

}


// Push new element to the stack

void Stack::push( int value )

{

    head.insert( new Node( value ) );

}


// Pop element from the stack

void Stack::pop()

{

    assert( !empty() );

    Node* obsolete = head.pnext;

    head.remove_next();

    delete obsolete;

}


// Writeable access to element on top of the stack

int& Stack::top()

{

    return head.pnext->data;

}


// Read-only access to element on top of the stack

int Stack::top() const

{

    return head.pnext->data;

}


// Return stack size

size_t Stack::size() const

{

    // minus one accounts for the head node

    return head.size() - 1;

}


// Return true if stack is empty

bool Stack::empty() const

{

    return head.size() == 1;

}


// Print contents of the stack

void print_stack( Stack const& st )

{

    if ( st.empty() ) {

       cout << "[0] (stack is empty)\n";


    } else {

        print_list( *st.head.pnext );

    }

}


int main(int argc, char* argv[])

{

    Stack st;

    print_stack( st );


    st.push( 10 );

    assert( st.size() == 1 );

    assert( st.top() == 10 );


    st.top() = 15; // assign top by other value

    assert( st.top() == 15 );


    st.push( 20 );

    assert( st.size() == 2 );

    assert( st.top() == 20 );

    print_stack( st );


    st.pop();

    assert( st.size() == 1 );

    assert( st.top() == 15 );

    print_stack( st );


    return 0;

}


Sample run:

[0] (stack is empty)

[2] 20 15

[1] 15

No comments:

Measure execution time with Julia, example using sorting algorithms

# random integers between 1 and 100 inclusive, generate thousands of them x = rand ( 1 : 100 , 100000 ) @time sort (x; alg=InsertionSort, r...