Add hb_set_t
diff --git a/TODO b/TODO
index d763c30..56eac54 100644
--- a/TODO
+++ b/TODO
@@ -85,6 +85,8 @@
 
 - GObject, FreeType, etc
 
+- hb_set_t
+
 
 Optimizations:
 =============
diff --git a/src/Makefile.am b/src/Makefile.am
index f53505e..63d4e31 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,6 +34,8 @@
 	hb-ot-name-table.hh \
 	hb-ot-tag.cc \
 	hb-private.hh \
+	hb-set-private.hh \
+	hb-set.cc \
 	hb-shape.cc \
 	hb-tt-font.cc \
 	hb-unicode-private.hh \
@@ -46,6 +48,7 @@
 	hb-buffer.h \
 	hb-common.h \
 	hb-font.h \
+	hb-set.h \
 	hb-shape.h \
 	hb-unicode.h \
 	hb-version.h \
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 8158df1..142eb5c 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -31,6 +31,7 @@
 
 #include "hb-ot-layout-private.hh"
 #include "hb-open-type-private.hh"
+#include "hb-set-private.hh"
 
 
 #define NO_CONTEXT		((unsigned int) 0x110000)
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index 32da46d..bf7e43b 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -95,51 +95,4 @@
 
 
 
-struct _hb_set_t
-{
-  void clear (void) {
-    memset (elts, 0, sizeof elts);
-  }
-  bool add (hb_codepoint_t g)
-  {
-    if (unlikely (g > MAX_G)) return false;
-    elt_t &e = elt (g);
-    elt_t m = mask (g);
-    bool ret = !!(e & m);
-    e |= m;
-    return ret;
-  }
-  bool has (hb_codepoint_t g) const
-  {
-    if (unlikely (g > MAX_G)) return false;
-    return !!(elt (g) & mask (g));
-  }
-  bool intersects (hb_codepoint_t first,
-		   hb_codepoint_t last) const
-  {
-    if (unlikely (first > MAX_G)) return false;
-    if (unlikely (last  > MAX_G)) last = MAX_G;
-    unsigned int end = last + 1;
-    for (hb_codepoint_t i = first; i < end; i++)
-      if (has (i))
-        return true;
-    return false;
-  }
-
-  private:
-  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;
-
-  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); }
-
-  elt_t elts[(MAX_G + 1 + (BITS - 1)) / BITS]; /* 8kb */
-  ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
-  ASSERT_STATIC (sizeof (elts) * 8 > MAX_G);
-};
-
 #endif /* HB_OT_LAYOUT_PRIVATE_HH */
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index 1c1e7d9..f6890b6 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -183,8 +183,6 @@
 hb_ot_layout_substitute_finish (hb_buffer_t  *buffer);
 
 
-typedef struct _hb_set_t hb_set_t;
-
 hb_bool_t
 hb_ot_layout_substitute_closure_lookup (hb_face_t      *face,
 				        hb_set_t *glyphs,
diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
new file mode 100644
index 0000000..4b24370
--- /dev/null
+++ b/src/hb-set-private.hh
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SET_PRIVATE_HH
+#define HB_SET_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-set.h"
+#include "hb-object-private.hh"
+
+
+
+struct _hb_set_t
+{
+  inline void clear (void) {
+    memset (elts, 0, sizeof elts);
+  }
+  inline bool add (hb_codepoint_t g)
+  {
+    if (unlikely (g > MAX_G)) return false;
+    elt_t &e = elt (g);
+    elt_t m = mask (g);
+    bool ret = !(e & m);
+    e |= m;
+    return ret;
+  }
+  inline bool del (hb_codepoint_t g)
+  {
+    if (unlikely (g > MAX_G)) return false;
+    elt_t &e = elt (g);
+    elt_t m = mask (g);
+    bool ret = !!(e & m);
+    e &= ~m;
+    return ret;
+  }
+  inline bool has (hb_codepoint_t g) const
+  {
+    if (unlikely (g > MAX_G)) return false;
+    return !!(elt (g) & mask (g));
+  }
+  inline bool intersects (hb_codepoint_t first,
+			  hb_codepoint_t last) const
+  {
+    if (unlikely (first > MAX_G)) return false;
+    if (unlikely (last  > MAX_G)) last = MAX_G;
+    unsigned int end = last + 1;
+    for (hb_codepoint_t i = first; i < end; i++)
+      if (has (i))
+        return true;
+    return false;
+  }
+
+  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;
+
+  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 */
+
+  ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
+  ASSERT_STATIC (sizeof (elts) * 8 > MAX_G);
+};
+
+
+
+#endif /* HB_SET_PRIVATE_HH */
diff --git a/src/hb-set.cc b/src/hb-set.cc
new file mode 100644
index 0000000..353489b
--- /dev/null
+++ b/src/hb-set.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-set-private.hh"
+
+
+
+static hb_set_t _hb_set_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  {0} /* elts */
+};
+
+
+hb_set_t *
+hb_set_create ()
+{
+  hb_set_t *set;
+
+  if (!(set = hb_object_create<hb_set_t> ()))
+    return &_hb_set_nil;
+
+  set->clear ();
+
+  return set;
+}
+
+hb_set_t *
+hb_set_get_empty (void)
+{
+  return &_hb_set_nil;
+}
+
+hb_set_t *
+hb_set_reference (hb_set_t *set)
+{
+  return hb_object_reference (set);
+}
+
+void
+hb_set_destroy (hb_set_t *set)
+{
+  if (!hb_object_destroy (set)) return;
+
+  free (set);
+}
+
+hb_bool_t
+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)
+{
+  return hb_object_set_user_data (set, key, data, destroy, replace);
+}
+
+void *
+hb_set_get_user_data (hb_set_t        *set,
+			 hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (set, key);
+}
+
+
+hb_bool_t
+hb_set_allocation_successful (hb_set_t  *set)
+{
+  return TRUE;
+}
+
+void
+hb_set_clear (hb_set_t *set)
+{
+  set->clear ();
+}
+
+hb_bool_t
+hb_set_has (hb_set_t       *set,
+	    hb_codepoint_t  codepoint)
+{
+  return set->has (codepoint);
+}
+
+void
+hb_set_add (hb_set_t       *set,
+	    hb_codepoint_t  codepoint)
+{
+  set->add (codepoint);
+}
+
+void
+hb_set_del (hb_set_t       *set,
+	    hb_codepoint_t  codepoint)
+{
+  set->del (codepoint);
+}
diff --git a/src/hb-set.h b/src/hb-set.h
new file mode 100644
index 0000000..a9c734b
--- /dev/null
+++ b/src/hb-set.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_SET_H
+#define HB_SET_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+
+typedef struct _hb_set_t hb_set_t;
+
+
+hb_set_t *
+hb_set_create (void);
+
+hb_set_t *
+hb_set_get_empty (void);
+
+hb_set_t *
+hb_set_reference (hb_set_t *set);
+
+void
+hb_set_destroy (hb_set_t *set);
+
+hb_bool_t
+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_user_data_key_t *key);
+
+
+/* Returns FALSE if allocation has failed before */
+hb_bool_t
+hb_set_allocation_successful (hb_set_t  *set);
+
+void
+hb_set_clear (hb_set_t *set);
+
+hb_bool_t
+hb_set_has (hb_set_t       *set,
+	    hb_codepoint_t  codepoint);
+
+void
+hb_set_add (hb_set_t       *set,
+	    hb_codepoint_t  codepoint);
+
+void
+hb_set_del (hb_set_t       *set,
+	    hb_codepoint_t  codepoint);
+
+/* TODO: add union, intersect, subtract, equal, empty, min, max, iter, etc */
+
+
+
+HB_END_DECLS
+
+#endif /* HB_SET_H */
diff --git a/src/hb.h b/src/hb.h
index 996dc91..d36040e 100644
--- a/src/hb.h
+++ b/src/hb.h
@@ -32,6 +32,7 @@
 #include "hb-buffer.h"
 #include "hb-common.h"
 #include "hb-font.h"
+#include "hb-set.h"
 #include "hb-shape.h"
 #include "hb-unicode.h"
 #include "hb-version.h"