Upgrade to latest harfbuzz
[framework/uifw/harfbuzz.git] / src / hb-private.hh
index b91595d..0cb049e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2007,2008,2009  Red Hat, Inc.
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 #ifndef HB_PRIVATE_HH
 #define HB_PRIVATE_HH
 
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "hb-common.h"
+#include "hb.h"
+#define HB_H_IN
+#ifdef HAVE_OT
+#include "hb-ot.h"
+#define HB_OT_H_IN
+#endif
 
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <assert.h>
 
@@ -45,8 +51,8 @@
  * someway around that. */
 #include <stdio.h>
 #include <errno.h>
+#include <stdarg.h>
 
-HB_BEGIN_DECLS
 
 
 /* Essentials */
@@ -55,16 +61,9 @@ HB_BEGIN_DECLS
 # define NULL ((void *) 0)
 #endif
 
-#undef FALSE
-#define FALSE 0
-
-#undef TRUE
-#define TRUE 1
-
 
 /* Basics */
 
-HB_END_DECLS
 
 #undef MIN
 template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
@@ -72,7 +71,6 @@ template <typename Type> static inline Type MIN (const Type &a, const Type &b) {
 #undef MAX
 template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
 
-HB_BEGIN_DECLS
 
 #undef  ARRAY_LENGTH
 #define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
@@ -80,12 +78,15 @@ HB_BEGIN_DECLS
 #define HB_STMT_START do
 #define HB_STMT_END   while (0)
 
-#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
-#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
-#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
+#define _ASSERT_STATIC1(_line, _cond)  typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC0(_line, _cond)  _ASSERT_STATIC1 (_line, (_cond))
+#define ASSERT_STATIC(_cond)           _ASSERT_STATIC0 (__LINE__, (_cond))
 
-#define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1]))
+#define ASSERT_STATIC_EXPR(_cond)((void) sizeof (char[(_cond) ? 1 : -1]))
+#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
 
+#define _PASTE1(a,b) a##b
+#define PASTE(a,b) _PASTE1(a,b)
 
 /* Lets assert int types.  Saves trouble down the road. */
 
@@ -103,6 +104,34 @@ ASSERT_STATIC (sizeof (hb_position_t) == 4);
 ASSERT_STATIC (sizeof (hb_mask_t) == 4);
 ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
 
+
+/* We like our types POD */
+
+#define _ASSERT_TYPE_POD1(_line, _type)        union _type_##_type##_on_line_##_line##_is_not_POD { _type instance; }
+#define _ASSERT_TYPE_POD0(_line, _type)        _ASSERT_TYPE_POD1 (_line, _type)
+#define ASSERT_TYPE_POD(_type)         _ASSERT_TYPE_POD0 (__LINE__, _type)
+
+#ifdef __GNUC__
+# define _ASSERT_INSTANCE_POD1(_line, _instance) \
+       HB_STMT_START { \
+               typedef __typeof__(_instance) _type_##_line; \
+               _ASSERT_TYPE_POD1 (_line, _type_##_line); \
+       } HB_STMT_END
+#else
+# define _ASSERT_INSTANCE_POD1(_line, _instance)       typedef int _assertion_on_line_##_line##_not_tested
+#endif
+# define _ASSERT_INSTANCE_POD0(_line, _instance)       _ASSERT_INSTANCE_POD1 (_line, _instance)
+# define ASSERT_INSTANCE_POD(_instance)                        _ASSERT_INSTANCE_POD0 (__LINE__, _instance)
+
+/* Check _assertion in a method environment */
+#define _ASSERT_POD1(_line) \
+       inline void _static_assertion_on_line_##_line (void) const \
+       { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
+# define _ASSERT_POD0(_line)   _ASSERT_POD1 (_line)
+# define ASSERT_POD()          _ASSERT_POD0 (__LINE__)
+
+
+
 /* Misc */
 
 
@@ -123,9 +152,11 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
 #if __GNUC__ >= 3
 #define HB_PURE_FUNC   __attribute__((pure))
 #define HB_CONST_FUNC  __attribute__((const))
+#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
 #else
 #define HB_PURE_FUNC
 #define HB_CONST_FUNC
+#define HB_PRINTF_FUNC(format_idx, arg_idx)
 #endif
 #if __GNUC__ >= 4
 #define HB_UNUSED      __attribute__((unused))
@@ -134,7 +165,11 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
 #endif
 
 #ifndef HB_INTERNAL
-# define HB_INTERNAL __attribute__((__visibility__("hidden")))
+# ifndef __MINGW32__
+#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
+# else
+#  define HB_INTERNAL
+# endif
 #endif
 
 
@@ -221,70 +256,24 @@ _hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
 typedef int (*hb_compare_func_t) (const void *, const void *);
 
 
-/* We need external help for these */
-
-#ifdef HAVE_GLIB
-
-#include <glib.h>
-
-typedef volatile int hb_atomic_int_t;
-#define hb_atomic_int_fetch_and_add(AI, V)     g_atomic_int_exchange_and_add (&(AI), V)
-#define hb_atomic_int_get(AI)                  g_atomic_int_get (&(AI))
-#define hb_atomic_int_set(AI, V)               g_atomic_int_set (&(AI), V)
-
-typedef GStaticMutex hb_mutex_t;
-#define HB_MUTEX_INIT                  G_STATIC_MUTEX_INIT
-#define hb_mutex_init(M)               g_static_mutex_init (&M)
-#define hb_mutex_lock(M)               g_static_mutex_lock (&M)
-#define hb_mutex_trylock(M)            g_static_mutex_trylock (&M)
-#define hb_mutex_unlock(M)             g_static_mutex_unlock (&M)
-
-#else
-
-#ifdef _MSC_VER
-#define _HB__STR2__(x) #x
-#define _HB__STR1__(x) _HB__STR2__(x)
-#define _HB__LOC__ __FILE__ "("_HB__STR1__(__LINE__)") : Warning Msg: "
-#pragma message(_HB__LOC__"Could not find any system to define platform macros, library will NOT be thread-safe")
-#else
-#warning "Could not find any system to define platform macros, library will NOT be thread-safe"
-#endif
-
-typedef volatile int hb_atomic_int_t;
-#define hb_atomic_int_fetch_and_add(AI, V)     ((AI) += (V), (AI) - (V))
-#define hb_atomic_int_get(AI)                  (AI)
-#define hb_atomic_int_set(AI, V)               HB_STMT_START { (AI) = (V); } HB_STMT_END
-
-typedef volatile int hb_mutex_t;
-#define HB_MUTEX_INIT                          0
-#define hb_mutex_init(M)                       HB_STMT_START { (M) = 0; } HB_STMT_END
-#define hb_mutex_lock(M)                       HB_STMT_START { (M) = 1; } HB_STMT_END
-#define hb_mutex_trylock(M)                    ((M) = 1, 1)
-#define hb_mutex_unlock(M)                     HB_STMT_START { (M) = 0; } HB_STMT_END
-
-#endif
-
-
-HB_END_DECLS
 
 
 /* arrays and maps */
 
 
+#define HB_PREALLOCED_ARRAY_INIT {0}
 template <typename Type, unsigned int StaticSize>
-struct hb_static_array_t {
-
+struct hb_prealloced_array_t
+{
   unsigned int len;
   unsigned int allocated;
   Type *array;
   Type static_array[StaticSize];
 
-  void finish (void) { for (unsigned i = 0; i < len; i++) array[i].finish (); }
+  void init (void) { memset (this, 0, sizeof (*this)); }
 
-  inline Type& operator [] (unsigned int i)
-  {
-    return array[i];
-  }
+  inline Type& operator [] (unsigned int i) { return array[i]; }
+  inline const Type& operator [] (unsigned int i) const { return array[i]; }
 
   inline Type *push (void)
   {
@@ -294,30 +283,28 @@ struct hb_static_array_t {
     }
     if (likely (len < allocated))
       return &array[len++];
+
     /* Need to reallocate */
     unsigned int new_allocated = allocated + (allocated >> 1) + 8;
-    Type *new_array;
+    Type *new_array = NULL;
+
     if (array == static_array) {
       new_array = (Type *) calloc (new_allocated, sizeof (Type));
-      if (new_array) {
+      if (new_array)
         memcpy (new_array, array, len * sizeof (Type));
-       array = new_array;
-      }
     } else {
       bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
-      if (unlikely (overflows))
-        new_array = NULL;
-      else
+      if (likely (!overflows)) {
        new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
-      if (new_array) {
-        free (array);
-       array = new_array;
       }
     }
-    if ((len < allocated))
-      return &array[len++];
-    else
+
+    if (unlikely (!new_array))
       return NULL;
+
+    array = new_array;
+    allocated = new_allocated;
+    return &array[len++];
   }
 
   inline void pop (void)
@@ -325,75 +312,151 @@ struct hb_static_array_t {
     len--;
     /* TODO: shrink array if needed */
   }
-};
-
-template <typename Type>
-struct hb_array_t : hb_static_array_t<Type, 2> {};
 
+  inline void shrink (unsigned int l)
+  {
+     if (l < len)
+       len = l;
+    /* TODO: shrink array if needed */
+  }
 
-template <typename Key, typename Value>
-struct hb_map_t
-{
-  struct item_t {
-    Key key;
-    /* unsigned int hash; */
-    Value value;
+  template <typename T>
+  inline Type *find (T v) {
+    for (unsigned int i = 0; i < len; i++)
+      if (array[i] == v)
+       return &array[i];
+    return NULL;
+  }
+  template <typename T>
+  inline const Type *find (T v) const {
+    for (unsigned int i = 0; i < len; i++)
+      if (array[i] == v)
+       return &array[i];
+    return NULL;
+  }
 
-    void finish (void) { value.finish (); }
-  };
+  inline void sort (void)
+  {
+    qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
 
-  hb_array_t <item_t> items;
+  inline void sort (unsigned int start, unsigned int end)
+  {
+    qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
 
-  private:
+  template <typename T>
+  inline Type *bsearch (T *key)
+  {
+    return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
+  template <typename T>
+  inline const Type *bsearch (T *key) const
+  {
+    return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+  }
 
-  inline item_t *find (Key key) {
-    if (unlikely (!key)) return NULL;
-    for (unsigned int i = 0; i < items.len; i++)
-      if (key == items[i].key)
-       return &items[i];
-    return NULL;
+  inline void finish (void)
+  {
+    if (array != static_array)
+      free (array);
+    array = NULL;
+    allocated = len = 0;
   }
+};
 
-  public:
 
-  inline bool set (Key   key,
-                  Value &value)
+#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
+template <typename item_t, typename lock_t>
+struct hb_lockable_set_t
+{
+  hb_prealloced_array_t <item_t, 2> items;
+
+  inline void init (void) { items.init (); }
+
+  template <typename T>
+  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
   {
-    if (unlikely (!key)) return NULL;
-    item_t *item;
-    item = find (key);
-    if (item)
-      item->finish ();
-    else
+    l.lock ();
+    item_t *item = items.find (v);
+    if (item) {
+      if (replace) {
+       item_t old = *item;
+       *item = v;
+       l.unlock ();
+       old.finish ();
+      }
+      else {
+        item = NULL;
+       l.unlock ();
+      }
+    } else {
       item = items.push ();
-    if (unlikely (!item)) return false;
-    item->key = key;
-    item->value = value;
-    return true;
+      if (likely (item))
+       *item = v;
+      l.unlock ();
+    }
+    return item;
   }
 
-  inline void unset (Key &key)
+  template <typename T>
+  inline void remove (T v, lock_t &l)
   {
-    item_t *item;
-    item = find (key);
-    if (!item) return;
+    l.lock ();
+    item_t *item = items.find (v);
+    if (item) {
+      item_t old = *item;
+      *item = items[items.len - 1];
+      items.pop ();
+      l.unlock ();
+      old.finish ();
+    } else {
+      l.unlock ();
+    }
+  }
 
-    item->finish ();
-    items[items.len - 1] = *item;
-    items.pop ();
+  template <typename T>
+  inline bool find (T v, item_t *i, lock_t &l)
+  {
+    l.lock ();
+    item_t *item = items.find (v);
+    if (item)
+      *i = *item;
+    l.unlock ();
+    return !!item;
   }
 
-  inline Value *get (Key key)
+  template <typename T>
+  inline item_t *find_or_insert (T v, lock_t &l)
   {
-    item_t *item = find (key);
-    return item ? &item->value : NULL;
+    l.lock ();
+    item_t *item = items.find (v);
+    if (!item) {
+      item = items.push ();
+      if (likely (item))
+        *item = v;
+    }
+    l.unlock ();
+    return item;
+  }
+
+  inline void finish (lock_t &l)
+  {
+    l.lock ();
+    while (items.len) {
+      item_t old = items[items.len - 1];
+       items.pop ();
+       l.unlock ();
+       old.finish ();
+       l.lock ();
+    }
+    items.finish ();
+    l.unlock ();
   }
 
-  void finish (void) { items.finish (); }
 };
 
 
-HB_BEGIN_DECLS
 
 
 /* Big-endian handling */
@@ -404,6 +467,14 @@ static inline uint16_t hb_be_uint16 (const uint16_t v)
   return (uint16_t) (V[0] << 8) + V[1];
 }
 
+/* Note, of the following macros, uint16_get is the one called many many times.
+ * If there is any optimizations to be done, it's in that macro.  However, I
+ * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
+ * results in a single ror instruction, does NOT speed this up.  In fact, it
+ * resulted in a minor slowdown.  At any rate, note that v may not be correctly
+ * aligned, so I think the current implementation is optimal.
+ */
+
 #define hb_be_uint16_put(v,V)  HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
 #define hb_be_uint16_get(v)    (uint16_t) ((v[0] << 8) + v[1])
 #define hb_be_uint16_eq(a,b)   (a[0] == b[0] && a[1] == b[1])
@@ -430,24 +501,249 @@ static inline unsigned char TOLOWER (unsigned char c)
                                  ((const char *) s)[3]))
 
 
+/* C++ helpers */
+
+/* Makes class uncopyable.  Use in private: section. */
+#define NO_COPY(T) \
+  T (const T &o); \
+  T &operator = (const T &o)
+
+
 /* Debug */
 
+
 #ifndef HB_DEBUG
 #define HB_DEBUG 0
 #endif
 
-static inline bool /* always returns TRUE */
-_hb_trace (const char *what,
-          const char *function,
-          const void *obj,
-          unsigned int depth,
-          unsigned int max_depth)
+static inline bool
+_hb_debug (unsigned int level,
+          unsigned int max_level)
+{
+  return level < max_level;
+}
+
+#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))
+
+template <int max_level> inline void
+_hb_debug_msg_va (const char *what,
+                 const void *obj,
+                 const char *func,
+                 bool indented,
+                 unsigned int level,
+                 int level_dir,
+                 const char *message,
+                 va_list ap)
+{
+  if (!_hb_debug (level, max_level))
+    return;
+
+  fprintf (stderr, "%-10s", what ? what : "");
+
+  if (obj)
+    fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj);
+  else
+    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
+
+  if (indented) {
+    static const char bars[] = "││││││││││││││││││││││││││││││││││││││││";
+    fprintf (stderr, "%2d %s├%s",
+            level,
+            bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), 3 * level),
+            level_dir ? (level_dir > 0 ? "╮" : "╯") : "╴");
+  } else
+    fprintf (stderr, "   ├╴");
+
+  if (func) {
+    /* If there's a class name, just write that. */
+    const char *dotdot = strstr (func, "::");
+    const char *space = strchr (func, ' ');
+    if (space && dotdot && space < dotdot)
+      func = space + 1;
+    unsigned int func_len = dotdot ? dotdot - func : strlen (func);
+    fprintf (stderr, "%.*s: ", func_len, func);
+  }
+
+  if (message)
+    vfprintf (stderr, message, ap);
+
+  fprintf (stderr, "\n");
+}
+template <> inline void
+_hb_debug_msg_va<0> (const char *what HB_UNUSED,
+                    const void *obj HB_UNUSED,
+                    const char *func HB_UNUSED,
+                    bool indented HB_UNUSED,
+                    unsigned int level HB_UNUSED,
+                    int level_dir HB_UNUSED,
+                    const char *message HB_UNUSED,
+                    va_list ap HB_UNUSED) {}
+
+template <int max_level> inline void
+_hb_debug_msg (const char *what,
+              const void *obj,
+              const char *func,
+              bool indented,
+              unsigned int level,
+              int level_dir,
+              const char *message,
+              ...) HB_PRINTF_FUNC(7, 8);
+template <int max_level> inline void
+_hb_debug_msg (const char *what,
+              const void *obj,
+              const char *func,
+              bool indented,
+              unsigned int level,
+              int level_dir,
+              const char *message,
+              ...)
 {
-  (void) ((depth < max_depth) && fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, depth, depth, function));
-  return TRUE;
+  va_list ap;
+  va_start (ap, message);
+  _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
+  va_end (ap);
 }
+template <> inline void
+_hb_debug_msg<0> (const char *what HB_UNUSED,
+                 const void *obj HB_UNUSED,
+                 const char *func HB_UNUSED,
+                 bool indented HB_UNUSED,
+                 unsigned int level HB_UNUSED,
+                 int level_dir HB_UNUSED,
+                 const char *message HB_UNUSED,
+                 ...) HB_PRINTF_FUNC(7, 8);
+template <> inline void
+_hb_debug_msg<0> (const char *what HB_UNUSED,
+                 const void *obj HB_UNUSED,
+                 const char *func HB_UNUSED,
+                 bool indented HB_UNUSED,
+                 unsigned int level HB_UNUSED,
+                 int level_dir HB_UNUSED,
+                 const char *message HB_UNUSED,
+                 ...) {}
+
+#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)      _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
+#define DEBUG_MSG(WHAT, OBJ, ...)                              _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL,    false, 0, 0, __VA_ARGS__)
+#define DEBUG_MSG_FUNC(WHAT, OBJ, ...)                         _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
+
+
+/*
+ * Trace
+ */
+
+template <int max_level>
+struct hb_auto_trace_t {
+  explicit inline hb_auto_trace_t (unsigned int *plevel_,
+                                  const char *what_,
+                                  const void *obj_,
+                                  const char *func,
+                                  const char *message,
+                                  ...) : plevel (plevel_), what (what_), obj (obj_), returned (false)
+  {
+    if (plevel) ++*plevel;
+
+    va_list ap;
+    va_start (ap, message);
+    _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
+    va_end (ap);
+  }
+  inline ~hb_auto_trace_t (void)
+  {
+    if (unlikely (!returned)) {
+      fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.  Level was %d.\n", plevel ? *plevel : -1);
+      _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
+      return;
+    }
+
+    if (plevel) --*plevel;
+  }
+
+  inline bool ret (bool v)
+  {
+    if (unlikely (returned)) {
+      fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
+      return v;
+    }
+
+    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, "return %s", v ? "true" : "false");
+    if (plevel) --*plevel;
+    plevel = NULL;
+    returned = true;
+    return v;
+  }
+
+  private:
+  unsigned int *plevel;
+  bool returned;
+  const char *what;
+  const void *obj;
+};
+template <> /* Optimize when tracing is disabled */
+struct hb_auto_trace_t<0> {
+  explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
+                                  const char *what HB_UNUSED,
+                                  const void *obj HB_UNUSED,
+                                  const char *func HB_UNUSED,
+                                  const char *message HB_UNUSED,
+                                  ...) {}
+
+  template <typename T>
+  inline T ret (T v) { return v; }
+};
+
+#define TRACE_RETURN(RET) trace.ret (RET)
+
+/* Misc */
+
+
+/* Pre-mature optimization:
+ * Checks for lo <= u <= hi but with an optimization if lo and hi
+ * are only different in a contiguous set of lower-most bits.
+ */
+template <typename T> inline bool
+hb_in_range (T u, T lo, T hi)
+{
+  if ( ((lo^hi) & lo) == 0 &&
+       ((lo^hi) & hi) == (lo^hi) &&
+       ((lo^hi) & ((lo^hi) + 1)) == 0 )
+    return (u & ~(lo^hi)) == lo;
+  else
+    return lo <= u && u <= hi;
+}
+
+
+/* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+ * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+#define FLAG(x) (1<<(x))
+
+
+template <typename T> inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+  if (unlikely (!len))
+    return;
+
+  unsigned int k = len - 1;
+  do {
+    unsigned int new_k = 0;
+
+    for (unsigned int j = 0; j < k; j++)
+      if (compar (&array[j], &array[j+1]) > 0) {
+        T t;
+       t = array[j];
+       array[j] = array[j + 1];
+       array[j + 1] = t;
+
+       new_k = j;
+      }
+    k = new_k;
+  } while (k);
+}
+
 
 
-HB_END_DECLS
 
 #endif /* HB_PRIVATE_HH */