next up previous contents index
Next: FileStat.h Up: The Sources Previous: MMap.h

SortedTable.h

// SortedTable.h
// a table of pointers to objects which is sortable by key
// 11/16/97 Mori Tetsuya
// 12/16/97 Add removeAll()

#ifndef __SortedTable_H
#define __SortedTable_H
#pragma interface "SortedTable.h"

#include <iostream.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#ifndef __BASIC_TYPES__
#define __BASIC_TYPES__
typedef int Integer32;
typedef Integer32 SizeType;
typedef Integer32 OffsetType;
typedef Integer32 CounterType;
typedef Integer32 ArenaID;
typedef Integer32 EntryID;
typedef Integer32 BoolType;
enum { True = 1, False = 0 };
typedef Integer32 ComparisonType;
enum { GreaterThan = 1, EqualTo = 0, LessThan = 1 };
typedef void *PointerType;

#endif // __BASIC_TYPES__

#define CACHE

template<class DerivedSortableObject, class Key>
class SortableObject {
public:
  virtual ~SortableObject() {}
  virtual ComparisonType compare(Key &k) = 0;
  virtual ComparisonType compare(DerivedSortableObject &o) = 0;
  virtual Key getKey() = 0;
  // static DerivedSortableObject nullObject; 
  virtual BoolType isNull() = 0;
};

// Object must be one of the basic objects of C++ language
// the Object itself is identical to its key
// null object is 0
template<class Object>
class SimpleSortableObject {
protected:
  Object obj;
public:
  SimpleSortableObject() {}
  SimpleSortableObject(Object o): obj(o) {}
  ~SimpleSortableObject() {}
  inline Object &operator =(Object o) {
    return obj = o;
  }
  inline int compare(Object &o) {
    // cout << "comparing " << obj << " with " << o << endl;
    return obj > o ? 1 : obj < o ? -1 : 0;
  }
  inline int compare(SimpleSortableObject &e) {
    // cout << "comparing " << obj << " with " << e.obj << endl;
    return obj > e.obj ? 1 : obj < e.obj ? -1 : 0;
  }
  inline Object getKey() {
    return obj;
  }
  static SimpleSortableObject nullObject;
  inline int isNull() {
    // cout << "investigating if " << obj << " is null" << endl;
    return obj == (Object)0;
  }
};

template <class Element, class Key> 
class SortedPointerTable {
protected:
  Element **table;
  SizeType size; // # of elements in the table
  SizeType allocatedSize; // # of affordable elements in the table
#ifdef CACHE
  Key      last;
  SizeType cache;
#endif
public:
  SortedPointerTable(Element **p, SizeType s) {
    if (!p) return;
    SizeType as;
    for (as = 1 << 7; as <= s; as <<= 1)
      ;
    if (table) {
      removeAll();
      delete table;
    }
    table = (Element **)new char[sizeof(Element *) * as];
    if (!table) return;
    allocatedSize = as;
    memcpy((void *)table, (void *)p, sizeof(Element *) * s);
    size = s;
    sortElements();
#ifdef CACHE
    cache = -1;
#endif
  }

  SortedPointerTable(SortedPointerTable &st) {
    if (st.table == 0) 
      return;
    SizeType as;
    for (as = 1 << 7; as <= st.size; as <<= 1)
      ;
    table = (Element **)new char[sizeof(Element *) * as];
    if (!table) return;
    allocatedSize = as;
    if (st.size > 0) {
      memcpy((void *)table, (void *)table, sizeof(Element *) * st.size);
    }
    size = st.size;
    sortElements();
#ifdef CACHE
    cache = -1;
#endif
  }

  SortedPointerTable(SizeType s = 1 << 7) {
    SizeType as;
    for (as = 1 << 7; as <= s; as <<= 1) 
      ;
    table = (Element **)new char[sizeof(Element *) * as];
    if (!table) return;
    allocatedSize = as;
    size = 0;
#ifdef CACHE
    cache = -1;
#endif
  }

  ~SortedPointerTable() {
    if (table) 
      delete (char *)table;
  }

  inline SizeType getSize() {
    if (table) 
      return size; 
    else 
      return 0;
  }

  inline SizeType getCapacity() {
    if (table)
      return allocatedSize;
    else
      return 0;
  }

  Element *findElement(Key key) {
    return (*this)[key];
  }

  inline Element *operator[](Key key) {
#ifdef CACHE
    if (cache >= 0 && key == last)
      return table[cache];
#endif
    SizeType index = searchByKey(key);
    if (index < size) {
      if (table[index]->compare(key) == 0) {
#ifdef CACHE
        last = key;
        cache = index;
#endif
        return table[index];
      } else {
        return 0;
      }
    } else {
      return 0;
    }
  }

  SizeType searchByKey(Key key) {
    if (size == 0)
      return 0;
    SizeType bottom = 0;
    SizeType top = size - 1;
    SizeType middle;
    int cmp;
    while (bottom < top) {
      middle = (bottom + top) / 2;
      cmp = table[middle]->compare(key);
      if (cmp < 0)
        bottom = middle + 1;
      else
        top = middle;
    }  
    // bottom == top
    cmp = table[bottom]->compare(key);
    if (cmp < 0)
      bottom++;

    // printStatus(key, bottom);
    return bottom;
  }

  SizeType searchByElement(Element *e) {
    if (size == 0)
      return 0;
    if (e == 0)
      return 0;
    SizeType bottom = 0;
    SizeType top = size - 1;
    SizeType middle;
    int cmp = 0;
    while (bottom < top) {
      middle = (bottom + top) / 2;
      cmp = table[middle]->compare(*e);
      if (cmp < 0)
        bottom = middle + 1;
      else
        top = middle;
    }  
    // bottom == top
    cmp = table[bottom]->compare(*e);
    if (cmp < 0)
      bottom++;

    return bottom;
  }

  inline Element *pickupElement(SizeType index) {
    return (*this)(index);
  }

  inline Element *operator()(SizeType index) {
    return (0 <= index && index < size) ? table[index] : 0;
  }

  Element *insertElement(Element *e) {
    return *this += e;
  }

  Element *operator+=(Element *e) {
    if (!e) return 0; // cannot insert null element
#ifdef CACHE
    cache = -1;
#endif
    SizeType index = searchByElement(e);
    if (index < size) {
      if (table[index]->compare(*e) <= 0)
        return 0; // elements must be unique or something is wrong
    }
    if(insertSpace(index) >= allocatedSize) 
      return 0;  // out of memory or something is wrong
    return table[index] = e;
  }
  
  inline Element *removeElement(Key key) {
    return *this -= key;
  }
    
  Element *operator-=(Key key) {
    SizeType index = searchByKey(key);
    if (index < size) {
      if (table[index]->compare(key) != 0) 
        return 0; // no elements with such key
#ifdef CACHE
      cache = -1;
#endif
      // find the element with the key
      Element *e = table[index];
      if (removeSpace(index) >= allocatedSize)
        return 0; // something is wrong
      return e; // removal is succesful
    } else {
      return 0; // Element e is bigger than the last
    }
  }

  inline Element *removeElement(Element *e) {
    return *this -= e;
  }

  Element *operator-=(Element *e) {
    SizeType index = searchByElement(e);
    if (index < size) {
      if (table[index]->compare(*e) != 0) 
        return 0; // no elements with such key
      // find the element with the key
#ifdef CACHE
      cache = -1;
#endif
      Element *e = table[index];
      if (removeSpace(index) >= allocatedSize)
        return 0; // something is wrong
      return e; // removal is succesful
    } else {
      return 0; // Element e is bigger than the last
    }
  }

  SizeType removeAll() {
#ifdef CACHE
    cache = -1;
#endif
    SizeType index;
    Element *e;
    for (index = 0; index < size; index++) {
      e = table[index];
      if (e != 0) {
        delete e;
      }
    }
    size = 0;
    return index;
  }
           
protected:
  static int compare(const void *a, const void *b) {
    return (*(Element **)a)->compare(**(Element **)b);
  }

  void sortElements() {
    qsort((void *)table, size, sizeof(Element *), compare);
  }    

  void printStatus(Key key, SizeType bottom) {
    SizeType i;
    cout << "size = " << size << endl;
    for (i = 0; i < size; i++) {
      cout << "[" << i << "] = " << table[i]->getKey() << endl;
    }
    cout << "searchByKey(" << key << ") = " << bottom << endl;
    cout << endl;
  }    

  SizeType insertSpace(SizeType index) {
    if (size < index) 
      return allocatedSize; // index is too high
    if (!(size < allocatedSize)) 
      grow(); // if there is no space left grow it

    if (!(size < allocatedSize)) 
      return allocatedSize; // unable to grow

    if (index < size) {
      memmove(&table[index + 1], &table[index], 
              sizeof(Element *) * (size - index + 1));
    } 
    size++;
    return index;
  }

  SizeType removeSpace(SizeType index) {
    if (size < index) 
      return allocatedSize;
    if (index < size - 1) {
      memmove(&table[index], &table[index + 1], 
              sizeof(Element *) * (size - index));
    }
    size--;
    return index;
  }

  void grow() {
    if (size < allocatedSize / 2)
      return;
    SizeType newas = allocatedSize << 1;
    Element **newtable = 
      (Element **)new char[sizeof(Element *) * newas];
    if (newtable == 0)
      return;
    memcpy((void *)newtable, (void *)table, sizeof(Element *) * size);
    delete (char *)table;
    table = newtable;
    allocatedSize = newas;
  }
};

template <class Element, class Key> 
class SortedObjectTable {
protected:
  Element *table;
  SizeType size; // # of elements in the table
  SizeType allocatedSize; // # of affordable elements in the table

#ifdef CACHE
  Key      last;
  SizeType cache;
#endif
public:
  SortedObjectTable(Element *p, SizeType s) {
    if (!p) return;
    SizeType as;
    for (as = 1 << 7; as <= s; as <<= 1)
      ;
    if (table) {
      removeAll();
      delete table;
    }
    table = (Element *)new char[sizeof(Element) * as];
    if (!table) return;
    allocatedSize = as;
    memcpy((void *)table, (void *)p, sizeof(Element) * s);
    size = s;
    sortElements();
#ifdef CACHE
    cache = -1;
#endif
  }

  SortedObjectTable(SortedObjectTable &st) {
    if (st.table == 0) 
      return;
    SizeType as;
    for (as = 1 << 7; as <= st.size; as <<= 1)
      ;
    table = (Element *)new char[sizeof(Element) * as];
    if (!table) return;
    allocatedSize = as;
    if (st.size > 0) {
      memcpy((void *)table, (void *)table, sizeof(Element) * st.size);
    }
    size = st.size;
    sortElements();
#ifdef CACHE
    cache = -1;
#endif
  }

  SortedObjectTable(SizeType s = 1 << 7) {
    SizeType as;
    for (as = 1 << 7; as <= s; as <<= 1) 
      ;
    table = (Element *)new char[sizeof(Element) * as];
    if (!table) return;
    allocatedSize = as;
    size = 0;
#ifdef CACHE
    cache = -1;
#endif
  }

  ~SortedObjectTable() {
    if (table) 
      delete (char *)table;
  }

  inline SizeType getSize() {
    if (table) 
      return size; 
    else 
      return 0;
  }

  inline SizeType getCapacity() {
    if (table)
      return allocatedSize;
    else
      return 0;
  }

  inline Element *getTable() {
    return table;
  }

  Element &findElement(Key key) {
    return (*this)[key];
  }

  inline Element &operator[](Key key) {
#ifdef CACHE
    if (cache >= 0 && key == last)
      return table[cache];
#endif
    SizeType index = searchByKey(key);
    if (index < size) {
      if (table[index].compare(key) == 0) {
#ifdef CACHE
        last = key;
        cache = index;
#endif
        return table[index];
      } else {
        return Element::nullObject;
      }
    } else {
      return Element::nullObject;
    }
  }

  SizeType searchByKey(Key key) {
    if (size == 0)
      return 0;
    SizeType bottom = 0;
    SizeType top = size - 1;
    SizeType middle;
    int cmp;
    while (bottom < top) {
      middle = (bottom + top) / 2;
      cmp = table[middle].compare(key);
      if (cmp < 0)
        bottom = middle + 1;
      else
        top = middle;
    }  
    // bottom == top
    cmp = table[bottom].compare(key);
    if (cmp < 0)
      bottom++;

    // printStatus(key, bottom);
    return bottom;
  }

  inline Element &pickupElement(SizeType index) {
    if (index >= size)
      return Element::nullObject; // index is out of range
    return table[index];
  }

  Element &operator()(SizeType index) {
    if (index >= size)
      return Element::nullObject; // index is out of range
    return table[index];
  }

  Element &insertElement(Element e) {
    return *this += e;
  }

  inline Element &operator+=(Element e) {
    if (e.isNull()) 
      return Element::nullObject; // cannot insert null element
    Key key = e.getKey();
    SizeType index = searchByKey(key);
    if (index < size) {
      if (table[index].compare(key) <= 0)
        return Element::nullObject; 
      // elements must be unique or something is wrong
    }
#ifdef CACHE
    cache = -1;
#endif
    if(insertSpace(index) >= allocatedSize) 
      return Element::nullObject;  // out of memory or something is wrong
    return table[index] = e;
  }
  
  Element removeElement(Key key) {
    return *this -= key;
  }
    
  inline Element operator-=(Key key) {
    SizeType index = searchByKey(key);
    if (index < size) {
      if (table[index].compare(key) != 0) 
        return Element::nullObject; // no elements with such key
      // find the element with the key
      Element e = table[index];
      if (removeSpace(index) >= allocatedSize)
        return Element::nullObject; // something is wrong
#ifdef CACHE
      cache = -1;
#endif
      return e; // removal is succesful
    } else {
      return Element::nullObject; // Element e is bigger than the last
    }
  }

  SizeType removeAll() {
    SizeType i;
#ifdef CACHE
    cache = -1;
#endif
    for (i = 0; i < size; i++) {
      table[i].~Element();
    }
    size = 0;
    return i;
  }

protected:
  static int compare(const void *a, const void *b) {
    return ((Element *)a)->compare(*(Element *)b);
  }

  void sortElements() {
    qsort((void *)table, size, sizeof(Element), compare);
  }    

  void printStatus(Key key, SizeType bottom) {
    SizeType i;
    cout << "size = " << size << endl;
    for (i = 0; i < size; i++) {
      cout << "[" << i << "] = " << table[i].getKey() << endl;
    }
    cout << "searchByKey(" << key << ") = " << bottom << endl;
    cout << endl;
  }    

  SizeType insertSpace(SizeType index) {
    if (size < index) 
      return allocatedSize; // index is too high
    if (!(size < allocatedSize)) 
      grow(); // if there is no space left grow it

    if (!(size < allocatedSize)) 
      return allocatedSize; // unable to grow

    if (index < size) {
      memmove(&table[index + 1], &table[index], 
              sizeof(Element) * (size - index + 1));
    } 
    size++;
    return index;
  }

  SizeType removeSpace(SizeType index) {
    if (size < index) 
      return allocatedSize;
    if (index < size - 1) {
      memmove(&table[index], &table[index + 1], 
              sizeof(Element) * (size - index));
    }
    size--;
    return index;
  }

  void grow() {
    if (size < allocatedSize / 2)
      return;
    SizeType newas = allocatedSize << 1;
    Element *newtable = 
      (Element *)new char[sizeof(Element) * newas];
    if (newtable == 0)
      return;
    memcpy((void *)newtable, (void *)table, sizeof(Element) * size);
    delete (char *)table;
    table = newtable;
    allocatedSize = newas;
  }
};
#endif // __SortedTable_H



Mori Tetsuya / t2y3141592@gmail.com