// ptrmap.h            see license.txt for copyright and terms of use
// map from KEY* to VALUE* for arbitrary types KEY and VALUE
// (neither are owned by the table)

// for const purposes, I regard the mapping itself as the only
// thing that cannot be modified in a "const" map; in particular,
// I allow a non-const VALUE* to be extracted

#ifndef PTRMAP_H
#define PTRMAP_H

#include "vptrmap.h"       // VoidPtrMap
#include "typ.h"           // NULL


template <class KEY, class VALUE>
class PtrMap {
private:     // data
  // underlying map implementation, around which this class
  // is a type-safe wrapper
  VoidPtrMap map;

public:      // funcs
  PtrMap()                         : map() {}
  ~PtrMap()                        {}

  // query # of mapped entries
  int getNumEntries() const        { return map.getNumEntries(); }
  bool isEmpty() const             { return getNumEntries() == 0; }
  bool isNotEmpty() const          { return !isEmpty(); }

  // if this key has a mapping, return it; otherwise, return NULL
  VALUE *get(KEY const *key) const { return (VALUE*)map.get((void const*)key); }

  // add a mapping from 'key' to 'value'; replaces existing
  // mapping, if any
  void add(KEY *key, VALUE *value) { map.add((void*)key, (void*)value); }

  // remove all mappings
  void empty()                     { map.empty(); }


public:      // iterators
  class Iter {
  private:     // data
    // underlying iterator state
    VoidPtrMap::Iter iter;

  public:      // fucs
    Iter(PtrMap<KEY,VALUE> const &map)   : iter(map.map) {}
    ~Iter()                              {}

    bool isDone() const            { return iter.isDone(); }
    void adv()                     { return iter.adv(); }

    // return information about the currently-referenced table entry
    KEY *key() const               { return (KEY*)iter.key(); }
    VALUE *value() const           { return (VALUE*)iter.value(); }
  };
  friend class Iter;
};


// a set based on PtrMap
template <class KEY>
  // dsw: I made the superclass public so I could iterate over it
  // using the superclass iterator
// class PtrSet : private PtrMap<KEY, KEY> {
class PtrSet : public PtrMap<KEY, KEY> {
  public:
  PtrSet() {}
  ~PtrSet() {}

  // query # of mapped entries
  int getNumEntries() const        { return PtrMap<KEY, KEY>::getNumEntries(); }
  bool isEmpty() const             { return PtrMap<KEY, KEY>::isEmpty(); }
  bool isNotEmpty() const          { return PtrMap<KEY, KEY>::isNotEmpty(); }

  // if this key has a mapping, return it; otherwise, return NULL
  bool contains(KEY const *key) const { return PtrMap<KEY, KEY>::get(key)!=NULL; }

  // add key to the set
  void add(KEY *key) { PtrMap<KEY, KEY>::add(key, key); }

  // make the set empty; FIX: this would be better named makeEmpty(),
  // as it could be confused with the meaning of isEmpty(); however I
  // reflect the naming of PtrMap, where the same criticism applies.
  void empty()                     { PtrMap<KEY, KEY>::empty(); }

  // dsw: I could not get this to compile; don't know why
// public:      // iterators
//   class Iter {
//   private:     // data
//     // underlying iterator state
//     ::PtrMap<KEY, KEY>::Iter iter;

//   public:      // fucs
//     Iter(PtrSet<KEY> const &set)   : iter(set) {}
//     ~Iter()                          {}

//     bool isDone() const            { return iter.isDone(); }
//     void adv()                     { return iter.adv(); }

//     // return information about the currently-referenced table entry
//     KEY *key() const               { return (KEY*)iter.key(); }
//     VALUE *value() const           { return (VALUE*)iter.value(); }
//   };
//   friend class Iter;
};


#endif // PTRMAP_H
