//
// 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: MBN 08/21/89 -- Initial design and implementation
// Updated: LGO 10/05/89 -- Make destructor inline
// Updated: LGO 12/04/89 -- Efficiency re-write
//
// The  parameterized  Range<Type,lbound,hbound> class is publicly derived from
// the Range class  and supports arbitrary  user-defined ranges  for a type  of
// object or built-in data type. This allows other higher level data structures
// such as  the Vector and  List container classes  to  be parameterized over a
// range of values for some  type so  that the programmer does  not have to add
// bounds checking code to the application. A Vector  of positive integers, for
// example, would  be easy  to declare, facilitating bounds checking restricted
// to the code that implements the type, not the Vector.
//
// The  inclusive  upper and  lower   bounds for   the  range are  specified as
// arguments  to the parameterized  type  declaration and  implementation macro
// calls.   They are declared  as C++ constants  of  the  appropriate type.  No
// storage is  allocated and all  references are compiled out by  the compiler.
// Once  declared, a Range<Type,lbound,hbound> object cannot  have its upper or
// lower bounds   changed,   since maintenance of all instances   would require
// significant and unwarranted overhead.  Each Range<Type,lbound,hbound> object
// has  a single private  data  slot that  holds ths instance value.  There are
// three constructors.   The first is  a simple  empty  constructor. The second
// accepts and sets an initial value.   The third  takes a reference to another
// Range<Type,lbound,hbound> object and duplicates its value.
//
// All  Range<Type,lbound,hbound>  methods  are  implemented   as small  inline
// functions to provide efficient encapsulation of objects,  including built-in
// types such as int.  Methods are provided to get  the  lower and upper bounds
// and set the value of the instance data  slot.  Assignment of  a value or one
// object to another is supported by the overloaded operator= method.  Finally,
// an implicit conversion  from a   Range<Type,lbound,hbound> object to a  Type
// value is provided to allow mixed expressions.
//

#ifndef RANGEH					// If no Range class
#define RANGEH

#ifndef BASE_RANGEH				// If no class definition
#include <cool/Base_Range.h>				// Include header file
#endif

MACRO Range_Quotify(arg) {#arg}

template <class Type, Type lbound, Type hbound> Range {
#ifndef Type##_Range_Compare_typedef // ensure no multiple definitions
#define Type##_Range_Compare_typedef
  typedef int (*Type##_Range_Compare) (const Type&, const Type&);
#endif
}

template <class Type, Type lbound, Type hbound>
class Range<Type,lbound,hbound> : public Range {
private:
  static Type low_bound;			// Class lower bound
  static Type high_bound;			// Class upper bound
  static Type##_Range_Compare compare_s;	// Pointer operator== function
  char* value_string() CONST;			// convert data to string
  void report_set_error () CONST;		// set method helper
  void do_compare () CONST;			// set method helper
  friend int Type##_Range_compare_data (const Type&, const Type&);
  Type data;					// Storage for instance value

public:
  Range<Type,lbound,hbound> ();			// Simple constructor
  Range<Type,lbound,hbound> (const Type& value); // Constructor with value
  Range<Type,lbound,hbound> (const Range<Type,lbound,hbound>&); // ref const.
  ~Range<Type,lbound,hbound> () {};			  // Destructor
  
  inline const Type& low () CONST;		// Get low value range
  inline const Type& high () CONST;		// Get high value range
  inline void set (const Type&);		// Set instance value

  inline Range<Type,lbound,hbound>&operator=(const Range<Type,lbound,hbound>&);
#ifdef __cplusplus
  inline operator Type () CONST;		// Implicit type conversion
#else
  inline Type operator Type ();			// Implicit type conversion
#endif
  inline void set_compare(Type##_Range_Compare);// Set Range compare function
};

#ifdef __cplusplus
// Initialize lower/upper bounds
template <class Type, Type lbound, Type hbound> Range {
Type Range<Type,lbound,hbound>::low_bound = lbound;
Type Range<Type,lbound,hbound>::high_bound = hbound;
}
#endif

// Range<Type,lbound,hbound> -- Simple constructor
// Input:         None
// Output:        None

template <class Type, Type lbound, Type hbound>
Range<Type,lbound,hbound>::Range<Type,lbound,hbound> () {
#ifndef __cplusplus
  this->low_bound = lbound;		// Set lower limit
  this->high_bound = hbound;		// Set upper limit
#endif
}


// Range<Type,lbound,hbound> -- Constructor with initial value
// Input:         Reference to value
// Output:        None

template <class Type, Type lbound, Type hbound>
Range<Type,lbound,hbound>::Range<Type,lbound,hbound> (const Type& value) {
#ifndef __cplusplus
  this->low_bound = lbound;		// Set lower limit
  this->high_bound = hbound;		// Set upper limit
#endif
  this->set(value);
}


// Range<Type,lbound,hbound> -- Constructor with reference to another range
//                object
// Input:         Reference to Range<Type,lbound,hbound> object
// Output:        None

template <class Type, Type lbound, Type hbound>
Range<Type,lbound,hbound>::Range<Type,lbound,hbound> (const Range<Type,lbound,hbound>& r) {
  this->data = r.data;				// Copy data value
}


// value_string -- method to convert value to string
// Input:         None
// Output:        string for value

template <class Type, Type lbound, Type hbound>
char* Range<Type,lbound,hbound>::value_string() CONST {
  extern char error_msg_buffer[];
  ostream str_stream(MSG_MAX, error_msg_buffer);
  str_stream << data;				// "print" value into buffer
  return strdup(error_msg_buffer);
}


// low -- Return a reference to lower limit to allow user to set/get value
// Input: None
// Output: Reference to lower limit

template <class Type, Type lbound, Type hbound>
inline const Type& Range<Type,lbound,hbound>::low () CONST {
  return this->low_bound;
}


// high -- Return a reference to upper limit to allow user to set/get value
// Input:  None
// Output: Reference to upper limit

template <class Type, Type lbound, Type hbound>
inline const Type& Range<Type,lbound,hbound>::high () CONST {
  return this->high_bound;
}

template <class Type, Type lbound, Type hbound>
void Range<Type,lbound,hbound>::report_set_error () CONST {
  if (this->data < this->low_bound)
    this->set_low_error (Range_Quotify(Range<Type, lbound, hbound>),
			 this->value_string());
  else if (this->data > this->high_bound)
    this->set_upper_error (Range_Quotify(Range<Type, lbound, hbound>),
			   this->value_string());
}
  
template <class Type, Type lbound, Type hbound>
void Range<Type,lbound,hbound>::do_compare () CONST {
  if ((*this->compare_s)(this->data, this->low_bound) < 0)      // Lower bounds
    this->set_low_error (Range_Quotify(Range<Type, lbound, hbound>),
			 this->value_string());
  else if ((*this->compare_s)(this->data, this->high_bound) > 0)// Upper bounds
    this->set_upper_error (Range_Quotify(Range<Type, lbound, hbound>),
			   this->value_string());
}

// set -- Set the value of the object
// Input:  Value to set
// Output: None

template <class Type, Type lbound, Type hbound>
inline void Range<Type,lbound,hbound>::set (const Type& value) {
  this->data = value;
  if (this->compare_s != NULL)			// When Custom compare function
    this->do_compare();
  else 						// Normal, fast case
   // check both bounds at once to minimize the amount of inline code
   if (value < this->low_bound || value > this->high_bound)
     this->report_set_error ();			// Raise exception
}


// operator= -- Overload the assignment operator to copy the value of one
//              Range<Type,lbound,hbound> object to another
// Input:       Reference to object
// Output:      Reference to updated object

template <class Type, Type lbound, Type hbound>
Range<Type,lbound,hbound>& Range<Type,lbound,hbound>::operator= (const Range<Type,lbound,hbound>& r) {
  this->data = r.data;				// Copy data value
  return *this;					// Return reference to object
}


// operator Type() -- Provide implicit conversion to what ever type this 
//                    class is parameterized over to allow mixed expressions
// Input:             None
// Output:            Value of object

template <class Type, Type lbound, Type hbound> Range {
#ifdef __cplusplus
inline Range<Type,lbound,hbound>::operator Type() CONST {return this->data;}
#else
inline Type Range<Type,lbound,hbound>::operator Type() {return this->data;}
#endif
}

// set_compare() -- Set the compare function for the Range class
// Input:           Pointer to a compare function
// Output:          None

template<class Type, Type lbound, Type hbound> 
inline void Range<Type,lbound,hbound>::set_compare (Type##_Range_Compare c) {
  this->compare_s = c;				// Set compare function
}

#endif						// End #ifdef of RANGEH
