Add a few more set operations

TODO: Tests for hb_set_t.
diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
index a6239e4..660aaee 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set-private.hh
@@ -38,6 +38,12 @@
   inline void clear (void) {
     memset (elts, 0, sizeof elts);
   }
+  inline bool empty (void) const {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
+      if (elts[i])
+        return false;
+    return true;
+  }
   inline void add (hb_codepoint_t g)
   {
     if (unlikely (g > MAX_G)) return;
@@ -64,19 +70,65 @@
         return true;
     return false;
   }
+  inline bool equal (const hb_set_t *other) const
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      if (elts[i] != other->elts[i])
+        return false;
+    return true;
+  }
+  inline void set (const hb_set_t *other)
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] = other->elts[i];
+  }
+  inline void union_ (const hb_set_t *other)
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] |= other->elts[i];
+  }
+  inline void intersect (const hb_set_t *other)
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] &= other->elts[i];
+  }
+  inline void subtract (const hb_set_t *other)
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] &= ~other->elts[i];
+  }
+  inline hb_codepoint_t min (void) const
+  {
+    for (unsigned int i = 0; i < ELTS; i++)
+      if (elts[i])
+	for (unsigned int j = 0; i < BITS; j++)
+	  if (elts[i] & (1 << j))
+	    return i * BITS + j;
+    return 0;
+  }
+  inline hb_codepoint_t max (void) const
+  {
+    for (unsigned int i = ELTS; i; i--)
+      if (elts[i - 1])
+	for (unsigned int j = BITS; j; j--)
+	  if (elts[i - 1] & (1 << (j - 1)))
+	    return (i - 1) * BITS + (j - 1);
+    return 0;
+  }
 
   typedef uint32_t elt_t;
   static const unsigned int MAX_G = 65536 - 1;
   static const unsigned int SHIFT = 5;
   static const unsigned int BITS = (1 << SHIFT);
   static const unsigned int MASK = BITS - 1;
+  static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
 
   elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
   elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
   elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
 
   hb_object_header_t header;
-  elt_t elts[(MAX_G + 1 + (BITS - 1)) / BITS]; /* 8kb */
+  elt_t elts[ELTS]; /* 8kb */
 
   ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
   ASSERT_STATIC (sizeof (elts) * 8 > MAX_G);
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 353489b..3b1c5bd 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -28,6 +28,8 @@
 
 
 
+/* Public API */
+
 static hb_set_t _hb_set_nil = {
   HB_OBJECT_HEADER_STATIC,
 
@@ -99,6 +101,12 @@
 }
 
 hb_bool_t
+hb_set_empty (hb_set_t *set)
+{
+  return set->empty ();
+}
+
+hb_bool_t
 hb_set_has (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
@@ -118,3 +126,50 @@
 {
   set->del (codepoint);
 }
+
+hb_bool_t
+hb_set_equal (hb_set_t *set,
+	      hb_set_t *other)
+{
+  return set->equal (other);
+}
+
+void
+hb_set_set (hb_set_t *set,
+	    hb_set_t *other)
+{
+  set->set (other);
+}
+
+void
+hb_set_union (hb_set_t *set,
+	      hb_set_t *other)
+{
+  set->union_ (other);
+}
+
+void
+hb_set_intersect (hb_set_t *set,
+		  hb_set_t *other)
+{
+  set->intersect (other);
+}
+
+void
+hb_set_subtract (hb_set_t *set,
+		 hb_set_t *other)
+{
+  set->subtract (other);
+}
+
+hb_codepoint_t
+hb_set_min (hb_set_t *set)
+{
+  return set->min ();
+}
+
+hb_codepoint_t
+hb_set_max (hb_set_t *set)
+{
+  return set->max ();
+}
diff --git a/src/hb-set.h b/src/hb-set.h
index a9c734b..35c77b8 100644
--- a/src/hb-set.h
+++ b/src/hb-set.h
@@ -52,14 +52,14 @@
 hb_set_destroy (hb_set_t *set);
 
 hb_bool_t
-hb_set_set_user_data (hb_set_t        *set,
+hb_set_set_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key,
 		      void *              data,
 		      hb_destroy_func_t   destroy,
 		      hb_bool_t           replace);
 
 void *
-hb_set_get_user_data (hb_set_t        *set,
+hb_set_get_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key);
 
 
@@ -71,6 +71,9 @@
 hb_set_clear (hb_set_t *set);
 
 hb_bool_t
+hb_set_empty (hb_set_t *set);
+
+hb_bool_t
 hb_set_has (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
 
@@ -82,8 +85,33 @@
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint);
 
-/* TODO: add union, intersect, subtract, equal, empty, min, max, iter, etc */
+hb_bool_t
+hb_set_equal (hb_set_t *set,
+	      hb_set_t *other);
 
+void
+hb_set_set (hb_set_t *set,
+	    hb_set_t *other);
+
+void
+hb_set_union (hb_set_t *set,
+	      hb_set_t *other);
+
+void
+hb_set_intersect (hb_set_t *set,
+		  hb_set_t *other);
+
+void
+hb_set_subtract (hb_set_t *set,
+		 hb_set_t *other);
+
+hb_codepoint_t
+hb_set_min (hb_set_t *set);
+
+hb_codepoint_t
+hb_set_max (hb_set_t *set);
+
+/* TODO: Add faster iteration API? */
 
 
 HB_END_DECLS