/* $Id: set.h,v 1.6 2008/05/15 15:36:04 post Exp $ */

#ifndef SET_H
#define SET_H

#include <ext/hash_map> 
#include <fstream>
#include <iostream>
#include <bitset>
#include <sstream>
using namespace std;
using namespace __gnu_cxx;

#define MAXSENTLEN 100

struct Span {
  Span() { min_ = max_ = 0; }
  Span(int min, int max) { min_ = min; max_ = max; }
  Span(int val) { min_ = max_ = val; }
  int min() const { return min_; }
  int max() const { return max_; }
  string str() const {
    stringstream ss;
    if (min_ != 0 || max_ != 0)
      ss << "[" << min_ << "-" << max_ << "]";
    return ss.str();
  }
  int min_, max_;

  friend Span& operator+=(Span&, int);
  friend Span& operator-=(Span&, int);

  friend struct hash_span;
  friend struct eq_span;
};
 
struct hash_span {
  size_t operator()(const Span& s) const {
    hash<int> i;
    return (i(s.min_) ^ i(s.max_));
  }
};
struct eq_span {
  bool operator()(const Span& s1, const Span& s2) const {
    return s1.min() == s2.min() && s1.max() == s2.max();
  }
};

Span operator+(const Span& a, const int b);
Span operator-(const Span& a, const int b);
ostream& operator<<(ostream& out, const Span& span);

struct Set {

  Set() { }

  Set(int s) {
    add(s,s);
  }

  Set(int s, int t) {
    add(s, t);
  }

  inline void add(int s, int t) {
    for (int i = s; i <= t; i++)
      bits[i] = 1;
  }
  inline void add(int w) { add(w,w); }

  inline void remove(int s, int t) {
    for (int i = s; i <= t; i++)
      bits[i] = 0;
  }
  inline void remove(int w) { remove(w,w); }

  inline int size() const {
    return bits.count();
  }

  int min() const { // don't work if remove was called!
    for (int i = 0; i < MAXSENTLEN; i++)
      if (bits[i]) return i;
    return -1;
  }

  int max() const {
    for (int i = MAXSENTLEN - 1; i >= 0; i--)
      if (bits[i]) return i;
    return -1;
  }

  inline void print_elements(ostream& out) const {
    int start = -1, end = -1;
    int first = 1;
    for (int i = 0; i <= MAXSENTLEN; i++) {
      if (bits[i]) {
        if (start == -1)
          start = i;
        end = i;
      } else {
        if (start != -1) {
          if (!first)
            out << ",";
          if (start == end)
            out << start;
          else
            out << start << "-" << end;
          start = -1;
          first = 0;
        }
      }
    }
  }

  friend struct hash_set;
  friend struct eq_set;
  friend ostream& operator<<(ostream&, const Set&);
  friend Set& operator+=(Set& set, const Set& other);
  friend Set operator+(const Set& set1, const Set& set2);
  friend bool operator==(const Set&, const Set&);

private:
  bitset<MAXSENTLEN> bits;
};

struct hash_set {
  size_t operator()(const Set& s) const {
    hash<char*> h;
    return h(s.bits.to_string().data());
  }
};

struct eq_set {
  bool operator()(const Set& s1, const Set& s2) const {
    return s1.bits == s2.bits;
  }
};

ostream& operator<<(ostream&, const Set&);
Set& operator+=(Set& set, const Set& other);
Set operator+(const Set& set1, const Set& set2);
bool operator==(const Set& set1, const Set& set2);
bool operator||(const Set& set1, const Set& set2); // intersection

#endif
