//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// Created: JCB 06/22/89 -- Design and implementation
// Updated: LGO 08/15/89 -- Removed operator>>
// Updated: MBN 08/20/89 -- Changed usage of template to reflect new syntax
// Updated: LGO 10/15/89 -- Added first & second
// Updated: LGO 10/15/89 -- Made get_first and get_second const 
// Updated: MBN 12/15/89 -- Added optional argument to set_compare method
// Updated: MJF 07/31/90 -- Added terse print
//
// The parameterized Pair<KeyT, ValueT> class implements an association between
// one object  and another. The objects  may  be of  different  types, with the
// first representing the  "key" of the  pair  and the second  representing the
// "value" of the pair. The Pair<KeyT, ValueT> class is used by the Association
// class to  implement  an a-list,  that  is a  vector   of pairs of associated
// values.
//
// The Pair<KeyT,  ValueT>  class is relatively  simple,  having only two  data
// slots. The first slot retains the key of the pair,  and the second holds the
// value.  There are three constructors for the class: a constructor that takes
// no arguments and creates an empty pair object; a  constructor that takes two
// initial values,  one  each for the  key  and  the value of  the  pair; and a
// constructor that takes a refernece to another Pair<KeyT, ValueT>  object and
// copies the values.
//
// Methods are provided to get and set the value of  the key and value objects,
// assign one Pair<KeyT, ValueT> object to anothher,  and test for equality and
// inequality between  two pairs. Finally  the output operator is overloaded to
// provide a means to display the value of a pair object.
//

#ifndef PAIRH
#define PAIRH

#ifndef MISCELANEOUSH		// If we have not included this file,
#include <cool/misc.h>		// include miscelaneous useful definitions.
#endif

#ifndef STREAMH			// If the Stream support not yet defined,
#if defined(DOS) || defined(M_XENIX)
#include <stream.hxx>           // include the Stream class header file
#else
#include <stream.h>		// include the Stream class header file
#endif
#define STREAMH
#endif

template <class T1, class T2> Pair {
  class Pair<T1,T2>;		// Forward reference class name
  typedef Boolean (*Pair<T1,T2>_Compare) (const Pair<T1,T2>&,
					       const Pair<T1,T2>&);
}

template <class T1, class T2>
class Pair<T1,T2> {
private:
  T1 firstd;					// First data slot
  T2 secondd;					// Second data slot
  static Pair<T1,T2>_Compare compare_s;		// Pointer operator== function
  friend Boolean Pair<T1,T2>_is_data_equal (const Pair<T1,T2>&,
						 const Pair<T1,T2>&); 
public:
  Pair<T1,T2> ();				// Pair p;
  Pair<T1,T2> (const T1&, const T2&);		// Pair p = (foo,bar);
  Pair<T1,T2> (const Pair<T1,T2>&);		// Pair p1 = p2;
  ~Pair<T1,T2> ();				// Destructor

  inline const T1& get_first () CONST;		// Get first element of pair
  inline const T2& get_second () CONST;		// Get second element of pair
  inline void set_first (const T1&);		// Set first element of pair
  inline void set_second (const T2&);		// Set second element of pair
  inline T1& first ();				// Get reference to 1st element
  inline T2& second ();				// Get reference to 2nd element

  Pair<T1,T2>& operator= (const Pair<T1,T2>&);	// Assignment p1 = p2;

  inline Boolean operator== (const Pair<T1,T2>&) CONST;  // is equal
  inline Boolean operator!= (const Pair<T1,T2>&) CONST;  // is not equal
 
  inline void set_compare(Pair<T1,T2>_Compare = NULL); // Set compare function

  friend ostream& operator<< (ostream&, const Pair<T1,T2>&); // Output operator
  inline friend ostream& operator<< (ostream&, const Pair<T1,T2>*);

  void print(ostream&);				// terse print
};

// get_first -- Return the first element of the pair
// Input:       None
// Output:      const Reference to the first element of the pair

template<class T1, class T2> 
inline const T1& Pair<T1,T2>::get_first () CONST {
  return this->firstd;
}


// get_second -- Return the second element of the pair
// Input:        None.
// Output:       const Reference to the second element of the pair

template<class T1, class T2> 
inline const T2& Pair<T1,T2>::get_second () CONST {
  return this->secondd;
}

// first -- Return the first element of the pair
// Input:       None
// Output:      Reference to the first element of the pair

template<class T1, class T2> 
inline T1& Pair<T1,T2>::first () {
  return this->firstd;
}


// second -- Return the second element of the pair
// Input:        None.
// Output:       Reference to the second element of the pair

template<class T1, class T2> 
inline T2& Pair<T1,T2>::second () {
  return this->secondd;
}


// set_first -- Set the first element of the pair
// Input:       Reference to a first element value
// Output:      None.

template<class T1, class T2> 
inline void Pair<T1,T2>::set_first (const T1& first) {
  this->firstd = first;
}


// set_second -- Set the first element of the pair
// Input:        Reference to a second element value
// Output:       None.

template<class T1, class T2> 
inline void Pair<T1,T2>::set_second (const T2& second) {
  this->secondd = second;
}


// set_compare -- Specify the comparison function to be used in logical tests
//                of the elements of pairs
// Input:         Pointer to compare function
// Output:        None

template<class T1, class T2> 
inline void Pair<T1,T2>::set_compare (Pair<T1,T2>_Compare c) {
  this->compare_s = c;
}


// operator== -- Return TRUE if this pair and another specified are equal
// Input:        Reference to a pair
// Output:       TRUE or FALSE

template<class T1, class T2> 
inline Boolean Pair<T1,T2>::operator== (const Pair<T1,T2>& p) CONST {
  return (*this->compare_s)(*this, p);
}


// operator!= -- Return TRUE if this pair and another specified are not equal
// Input:        Reference to a pair
// Output:       TRUE or FALSE

template<class T1, class T2> 
inline Boolean Pair<T1,T2>::operator!= (const Pair<T1,T2>& p) CONST {
  return !(*this->compare_s)(*this, p);
}


// Pair -- Empty constructor
// Input:  None.
// Output: None.

template<class T1, class T2> 
Pair<T1,T2>::Pair<T1,T2> () {
 if (this->compare_s == NULL)			// if no compare function
   this->compare_s = &Pair<T1,T2>_is_data_equal; // default
}


// Pair (T1,T2) -- Constructor that initializes the first and second elements
// Input:          Reference to first value, reference to second value
// Output:         None.  

template<class T1, class T2> 
Pair<T1,T2>::Pair<T1,T2> (const T1& first, const T2& second) {
  this->firstd = first;
  this->secondd = second;
  if (this->compare_s == NULL)			// if no compare function
    this->compare_s = &Pair<T1,T2>_is_data_equal; // default
}


// Pair (Pair) -- Constructor for reference to another pair
// Input:         Reference to another pair
// Output:        None.

template<class T1, class T2> 
Pair<T1,T2>::Pair<T1,T2> (const Pair<T1,T2>& p) {
  this->firstd = p.firstd;
  this->secondd = p.secondd;
  if (p.compare_s == NULL)		       // if no compare function
    this->compare_s = &Pair<T1,T2>_is_data_equal; // default
  else this->compare_s = p.compare_s;		  // else use other pair's
}


// ~Pair -- Destructor for pair does nothing
// Input:         None.
// Output:        None.

template<class T1, class T2> 
Pair<T1,T2>::~Pair<T1,T2> () {;}


// is_data_equal -- Default data comparison function if user has not provided
//                  another one. 
// Input:           Two references to pairs
// Output:          TRUE or FALSE

template<class T1, class T2> Pair {
  Boolean Pair<T1,T2>_is_data_equal (const Pair<T1,T2>& p1, 
				          const Pair<T1,T2>& p2) {
    return ((p1.firstd == p2.firstd) && (p1.secondd == p2.secondd));
  }
}


// operator= -- Assigns this pair to another
// Input:  Reference to another pair
// Output: Reference to the copied pair

template<class T1, class T2> 
Pair<T1,T2>& Pair<T1,T2>::operator= (const Pair<T1,T2>& p) {
  this->firstd = p.firstd;
  this->secondd = p.secondd;
  return *this;
}


// operator<< -- Overload output operator for the pair class
// Input:        Pointer to a pair object, reference to an output stream
// Output:       Reference to an output stream

template<class T1, class T2> Pair {
inline ostream& operator<< (ostream& os, const Pair<T1,T2>* p) {
  return operator<< (os, *p);
}
}


// operator<< -- Output a pair
// Input:        Reference to an ostream, reference to a pair
// Output:       Reference to the modified ostream

template<class T1, class T2> Pair {
ostream& operator<< (ostream& os, const Pair<T1,T2>& p) {
  os << "[" << p.firstd << " " << p.secondd << "] ";
  return os;
}
}


// print --  terse print function for Pair
// Input:    reference to output stream
// Output:   none

template<class T1, class T2>
void Pair<T1,T2>::print (ostream& os) {
  os << form("/* Pair %lx */", (long) this);
}

#endif  // End #ifndef PAIRH
