--- ToDo list Dec 1992 by Jamshid Afshar (jamshid@emx.utexas.edu) ---

o ascii_duration() is stupid about years  1 Jan 1992 - 31 Dec 1991 is
*not* "1 year 1 day".

o Fix bugs in random, quaternion, and complex -- code probably
assumes 32-bit ints.  Their test_*.C programs have bugs which crash
the machine, so I commented them out of the tests\makefile.

o Turn inlining back on (-vi) once I get a BC++ that inlines without
causing weird run-time bugs.

o Get rid of Envelope class.  Besides probably not being strictly
valid C++ because it relies on temporaries hanging around, I think
compiler optimizations could reap a lot of its benefits.  Also, maybe
same optimization could be done less obscurely by using Shared data
members instead.

o Why is NT_Stack_Entry first_element a long instead of a pointer?!

o Change Range<Bounds> back to Range<T, T max, T min> since this is
legal after all (a BC++ 3.1 bug didn't allow original code). (that's
why ex3_12 is commented out in examples/makefile).

o Remove all use of <values.h> -- use INT_MIN,etc. instead of MAXINT,etc.
(mostly just in Complex and Rational)

o Change all #include <misc.h> to #include <cool/misc.h> so don't have
to have cool and cool/.. in path.  Maybe rename (or remove) Boolean.

o Get rid of (int n, Type t, ...) ctors in List, Vector, etc. since
they cause overloading ambiguities and they're rarely useful (only
built-in types).

o Get rid of all the "== TRUE" tests in (*compare)() calls.  Add
template parameter Comparator instead of using compare functions

o For all array indexes change ulong->size_t, long->size_t but check
arithmetic since sometimes relies on negative values.

o Redo error handling; code relies on coolcpp's ability to to
stringize template parameter name; do something upwardly compatible
with throw (maybe something like Johan Bengston's paper).

o Use CoolList_H instead of LISTH as macro wrapper so as not to
conflict with other List.h headers.  Also get rid of #ifndef around
each #include statement -- let the compiler do this optimization.

o Possibly #include <cool/*.C> in each header file unless next version
of compilers implement automatic instantiation of template functions.

o Maybe change to more modern, POSIX Regexp?



---- The following is the todo list that was in the GECOOL2.1 package ----

File: List.h

  Create nodes with a reference count of 1, then eliminate all the
  reference method calls on new nodes. (new nodes are ALWAYS referenced
  by something...)
done - LGO 10/2/89

1. Fix bug in division and modulo of 2 bignums.
	Reason: Overflow is not always catched with fixnum multiplication.
	Fix in estimate_q_hat.
DONEFile: Date_Time.C

localtime(long) has 1 array bound write error and "delete (tm*) t" causes
warings from Purify: freeing t which is not the begining of a malloc bloc.
IGNORE

Fix memory leak caused by tzset() called in set_tz(time_zone).
This call is done by localtime already, and only once.
DONE


Vector.h
 Bug in ... in constructor, using va_arg.
 The arguments in ... cannot be passed by reference. macro va_arg does funny
 casting and does not enforce argument passing correctly, especially in case
 of passing by reference.

prepend, remove_duplicates
 Don't call constructors or operator= on the elements of this->data


 operator[], fill, copy
 When checking array boundaries, instead of
   if (n < 0 || n >= this->number_elements)	// If index out of range
 do:
   if ((unsigned long) n >= this->number_elements)
 The cast makes negative n look very large.
DONE

 operator==, position, search, push_new, remove, remove_duplicates, replace,
 replace_all
 This sits in a loop calling (*this->compare).  Instead, make this->compare
 default to NULL, and have two loops: one for the default case where
 operator== on the value type is used, and another calling (*this->compare).
operator== and search are special cases
DONE

 search, push_new, remove, remove_duplicates, replace, replace_all
 there ought to be a general purpose, protected searching method, which is
 fast (see above) used by all these methods.
Used find - DONE

 copy, push, push_new, append, prepend, insert_before, insert_after
 There needs to be a general purpose protected grow method, like in String.
 The grow method should call resize to do most of the work.
DONE

 reverse
 This could be re-written to use pointers instead of indices.
 Dividing the length by two can be eliminated, and a check for when
 the top and bottom pointers meet or cross substituted.

 remove, remove_duplicates, prepend, insert_before, insert_after
 These need to be re-written to do their work in-place (i.e. no copying
 to a temporary)  The new and delete calls should go away.
DONE - prepend left as-is because it's likely to grow the vector

 insert_before, insert_after
 There are two versions of each of these.  They should all call a common
 private method which does the real work of inserting something at some index.
DONE

 type##_vector_heap_sort
 This needs to be merged into the sort method.  There's no reason for
 this friend function to exist, and it causes an extra .o file to be
 produced by the implement script.
DONE

 sort
 Use the ansi C qsort function, instead of having one in the template.
 If you feel that the heap sort algorithm is superior, write a general
 purpose hsort function, with the same calling sequence as qsort.
 hsort can be in the library instead of the template.
DONE

 Vector<Type>(int n, Type* data)
 Write a new constructor which makes a fixed size vector which shares
 storage with the data argument
DONE

Matrix.h
 Bug in ... in constructor, using va_arg.
 The arguments in ... cannot be passed by reference. macro va_arg does funny
 casting and does not enforce argument passing correctly, especially in case
 of passing by reference.

  In all the constructors:
  Allocate all the column data in one chunk, then fill in the
  addresses in the row vector.
DONE

  ~Matrix, operator=, 
  When deleting the matrix, delete only the first row, then the column
  (see above)
DONE

  operator+ operator* etc. (All non-destructive operators)
  DON'T RETURN A REFERENCE TO STORAGE ON THE HEAP.  Return a Matrix on
  the stack by value.  Use the copy constructor, then the associated
  operator?= function.
DONE

  operator*=
  This allocates row vectors on the heap, then doesn't delete them!
  Anyway, this needs to be re-written to use a single temporary row
  vector, instead of a whole new matrix.

  inline Type& operator[](int row, int col)
  New method, does the same thing as the current get method.
DONE

  inline const Type& get (int, int);
  change this to return Type, instead of a const reference to type.
  (We're always dealing with numbers, right? so there's no need to
  deal in references to Type.)
DONE
  
  Nuke the map and reduce methods
DONE

File: Stack.h

Fix memory leak, in &=, |=, ^=, -=. 
The leak comes from returning by value, a stack allocated on the heap.
The stack is copied and returned, and the one on the heap is never deleted.
DONE

Add a general purpose protected grow method
DONE

  push pushn
  use the grow method.
DONE

 operator==, find, position
 These sit in a loop calling (*this->compare).  Instead, make this->compare
 default to NULL, and have two loops: one for the default case where
 operator== on the value type is used, and another calling (*this->compare).
DONE

 Stack<Type>(int n, Type* data)
 Write a new constructor which makes a fixed size Stack which shares
 storage with the data argument.
DONE
Queue.h

  unget, put
  Call a general purpose grow method, which calls resize to do most of
  the work. 
DONE

  remove
  Rewrite to remove in-place, instead of copying the whole queue.
DONE

  set_length
  Currently, if the length specified is greater than the size, the
  length is set to the size.  This is wrong.  It should resize the
  queue to be large enough for length.

  The whole implementation is inefficient.  number_elements should NOT
  be maintained, but calculated.  Things like get and put should be
  trivial inlines, not 20 line functions.
DONE

  I think the names first_in and last_in are confusing.  I would call
  them in and out.
DONE

  In addition, since queue always works sequentially,
  it's better to use pointers instead of array references [].


  There needs to be additional overloaded versions of get and unput, which
  take a reference to a return value, and return a Boolean success flag.
DONE
file: Association.h

find
  re-write this to not use reset next and key.  find is heavily used,
  and setting current position inside the loop (instead of using a local
  variable in a register) slows it down
template <class Ktype, class Vtype>
Boolean Association<Ktype,Vtype>::find (const Ktype& key) {
  for (long i = 0; i < this->number_elements; i++) // Search for key in list
   if ((*this->compare_keys_s)(this->data[i].get_first(), key) == TRUE) {
     this->current_position = i;	// Set current position		
     return TRUE;			// Return success
    }
  return FALSE;				// Return failure
}

remove()
  re-write to invoke the base class remove() method.

remove (const Ktype& key)
  re-write to do a find(key) followed by remove()

put
  put needs to call the general purpose protected grow method, that
  Vector should have (see cool/Vector/TODO)


Make the (base) ~Hash_Table() destructor method inline.

Get rid of the Hash_Table<Tkey,Tval>::Hash_Table<Tkey,Tval> () constructor
and give the constructor that takes a size a default argument:
Hash_Table<Tkey,Tval>::Hash_Table<Tkey,Tval> (int n=1) : (n) {
Do the same for the base Hash_Table class.

Move the "traversed" flag in the current position out of Hash_Table, and
only support it in the Set class.

Use the following for setting current position:
#define make_current_position(hash, index) ((hash << 8) | index)
this->current_position.data = make_current_position(hash, index);
This helps out compilers that don't optimize well (-g option)
and will be faster, if the "traversed" flag is left in.

The resize method can be improved by using the overloaded operator new
in cfront 2.0 to only construct the new buckets, avoid calling the
destructor for the old buckets, and avoid operator= by using memcpy (see
Vector<Type>::resize)

Don't try saving the current position in the remove method.  Since it
doesn't always work, it should never be done.

Re-write Boolean Hash_Table<Tkey,Tval>::remove (const Tkey& key);
to do a find(key) followed by remove();
(this reduces the amount of code generated for each hash table)

Operator= shouldn't make the sizes of the two hash tables the same,
it should just copy the contents.  The current algorithm should be
an optimization for the case where the two sizes are already equal,
or less than.

Operator== shouldn't depend on the two hash table's having the same
number of buckets.  It should first check for the number of entries
being the same (which it does), then for each element in the first hash
table, do a find on the second, and compare the values.  The current
algorithm should be used as an optimization for the case where the two
hash tables have the same number of buckets.
DONE

find, put, get and remove all have the following inner-loop code:
  long prime = hash_primes[this->current_bucket]; // Prime number of buckets
  unsigned long hash = ((*this->h_function)(key)) % prime; // Get hash value
  int index = this->items_in_buckets[hash];
  for (int i = 0; i < index; i++)		// For each item
    if ((*this->compare_keys)(key,this->table[hash].data[i].key) == TRUE)
      //DO SOMETHING

Get rid of the function call in the inner loop by making compare_keys
default to NULL, and moving the default code to a general purpose find
method.  Do the same for default_hash.
The above code can be replaced with:

  unsigned long hash;
  int i = this->internal_find(key, &hash);
  if (i < 0) DO_SOMETHING
  else DO_SOMETHING_ELSE

// Returns bucket index, or -1 if not found
// If hash_return is non-null, return the hash value
// If hash_return is null, this function returns the hash value
// (this feature is used by the resize method)

long Hash_Table<Tkey, Tval>::internal_find(Tkey key, long* hash_return) {
  long prime = hash_primes[this->current_bucket]; // Prime number of buckets
  long hash;
  //
  // Get the hash value
  //
  if (this->h_function != NULL)
    hash = ((*this->h_function)(key)) % prime;
  else {
#if ISSAME(Tkey, charP) || ISSAME(Tkey, String)
    hash = sxhash(key) % prime;
#else
    if (sizeof (key) <= 4)
      hash = (((unsigned long) key) >> 3) % prime;
    else
      hash = sxhash((char*) &key) % prime;
#endif
  }
  if (hash_return == NULL)
    return hash;
  else
    hash_return = hash;
  //
  // Find the bucket entry
  //
  int index = this->items_in_buckets[hash];
  Tkey##_##Tval##_hash_pair bucket[BUCKET_SIZE] = this->table[hash].data;
  if (this->compare_keys == NULL) {	// DEFAULT COMPARE FUNCTION
#if ISSAME(T1, charP)
 #ifndef C_STRINGH
   extern int strcmp (const char*, const char*);
 #endif
    for (int i = 0; i < index; i++)		// For each item
      if (!strcmp(key,bucket[i].key))
        return i;
#else
    for (int i = 0; i < index; i++)		// For each item
      if (key == bucket[i].key)
        return i;
#endif

  } else {				// VARIABLE COMPARE FUNCTION
    for (int i = 0; i < index; i++)		// For each item
      if ((*this->compare_keys)(key, bucket[i].key))
        return i;
  }
  return -1;
}

This method replaces default_hash and Default_Hash_Compare.  In
addition, it eliminates several function calls in all the lookup
methods, and reduces code duplication (i.e. reduces the amount of code
generated for each hash table)
File: Set.h

Enforce const for set operations + - ^ |, etc...
Currently, const cannot be enforced because the curpos pointer changes.
Save curpos and restore it, so that const is enforced.
DONE

********
*** All the comments in cool/Hash_Table/TODO apply to Set
********

operator| operator^
  These can be re-written to copy "this" to a temporary, and call
  the matching operator|= or operator^= method.
  For example:

template <class Type> 
Set<Type> Set<Type>::operator| (Set<Type>& s) {
  Set<Type> result(this->length() + s.length()); // Temporary variable
  for (this->reset(); this->next (); )		// For each entry in 1st set
    result->put (this->value());		// Put entry to result set
  result.operator|=(s);
  return result;				// Return resulting union
}

test_Set depends on the hash sequence of the Sun/4.  This needs to be fixed.
1. Check AVL tree for balancing after put and remove. ex9_7.C
   the tree can be balanced further...

All files:

Split the template files into header (.h) and source (.C). 
Eliminate Coolcpp syntax, and make all templates conformant to AT&T C++ 3.0,
and GNU g++ 2.0.

Efficient initialization in constructors by passing initial values to slots
directly, rather that making assignments in body of constructors.

Implement association and other classes based on stack rather than vector,
since LIFO is usally a better than FIFO. Currently there is a lot of shuffling
and copying inside of vector, each time an element is inserted or deleted.


Make sure that operator= works if left hand side is the same object as right 
hand side of =.
DONE

A lot of COOL objects copy by ints, and so create array bounds, read writes
on free memory, when the sizeof(object) is not an integral multiplier of
sizeof(int).
Use Purify to check for access errors.
DONE

Fix memory leaks, using infinite loop and watching memory usage with top4.1.
Use Purify to check for leaks.
DONE



All files:

Either implement sharing of nodes in the trees, or do explicit copy.
Currently the trees share the nodes without any reference count.
Choose to do explicit deep copy for now.
DONE

Fix memory leak for Binary_Tree and N_Tree.
Make destructor virtual where necessary.
DONE 

File AVL_Tree.h:

Fix balancing bug in AVL tree.
see ../examples/section9/ex9_7.C for bug occurence.
./list/todo
./bignum/todo
./date_tim/todo
./vector/todo
./matrix/todo
./stack/todo
./queue/todo
./associat/todo
./hash_tab/todo
./set/todo
./examples/section9/todo
./todo
./tree/todo
