// leda_impl2.C
// ----------------------------------------------------------------
// COMP 290-001: Algorithm Library Design, Lutz Kettner, 01/11/2000
// Example for LEDA data structure implementations with an implementation
// parameter. This is an example continued from leda_impl.C. An alternative
// implementation for the simple ordered pair is offered.

#include <assert.h>

// Base class working on void* pointers. Can be precompiled and
// put in the library. For simplicity, it is implemented inline here.

class pair_impl {
    void* d_min;
    void* d_max;
protected:  // this class is only ment for derivation
    // to be implemented in derived class:
    virtual bool cmp( void* a, void* b) = 0; 
    // note, constructor doesn't work here instead of set() because
    // the virtual cmp function wouldn't be available (will be available
    // after derived class is constructed).
    void set( void* a, void* b) { 
	if ( cmp(a,b)) {
	    d_min = a;
	    d_max = b;
	} else {
	    d_min = b;
	    d_max = a;
	}
    }
    void* min() { return d_min; }
    void* max() { return d_max; }
};

// Another base class for the alternative implementation.

class pair_impl_2 {
    void* d_a;
    void* d_b;
protected:  // this class is only ment for derivation
    // to be implemented in derived class:
    virtual bool cmp( void* a, void* b) = 0; 
    void set( void* a, void* b) { 
	d_a = a;
	d_b = b;
    }
    void* min() { return cmp(d_a, d_b) ? d_a : d_b; }
    void* max() { return cmp(d_a, d_b) ? d_b : d_a; }
};

// Derived class template. Knows the actual type and implements the
// comparison function. Does convert between type and void* pointers.
// Resides in header file. Almost all functions are usually inline 
// and short. Deals also with dynamic allocation and deletion of the
// items. Derivation is private, since derivation is only needed as
// an implementation technique to implement the comparison function 
// easily.

// Now, its member function are also made virtual to allow proper
// interaction with the newly derived class template with implementation
// parameter, see below.

template <class T>
class pair : private virtual pair_impl {
    virtual bool cmp( void* a, void* b) { 
	// use casts to T
	return * static_cast<T*>(a) < * static_cast<T*>(b);
    }
public:
    pair() {}
    pair( const T& a, const T& b) { set( new T(a), new T(b)); }
    virtual T& min() { return * static_cast<T*>( pair_impl::min()); }
    virtual T& max() { return * static_cast<T*>( pair_impl::max()); }
};

// The newly derived class template with an additional template argument
// for the implementation. Since we derive from two different 
// implementations, Impl and the one from pair, we better make them
// virtual base classes (could be the same), and qualify explicitly
// of which base class we want to call member functions.
// Note, this is also a (not so) obvious disadvantage: since we inherit
// two implementations, we actually carry one useless implementation 
// around (and waste memory).

template <class T, class Impl>
class pair_x : private virtual Impl, public pair<T> {
    virtual bool cmp( void* a, void* b) { 
	// use casts to T
	return * static_cast<T*>(a) < * static_cast<T*>(b);
    }
public:
    pair_x( const T& a, const T& b) { Impl::set( new T(a), new T(b)); }
    virtual T& min() { return * static_cast<T*>( Impl::min()); }
    virtual T& max() { return * static_cast<T*>( Impl::max()); }
};

int main() {
    {
	pair<int> p(5, 8);
	assert( p.min() == 5);
	assert( p.max() == 8);
    }{
	// Same as above, but giving implementation explicitly.
	pair_x<int,pair_impl> p(5, 8);
	assert( p.min() == 5);
	assert( p.max() == 8);
    }{
	// Changed implementation.
	pair_x<int,pair_impl_2> p(5, 8);
	assert( p.min() == 5);
	assert( p.max() == 8);
    }
}

