Upgrade to latest harfbuzz
[framework/uifw/harfbuzz.git] / src / hb-private.hh
index b5745e7..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,13 +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. */
 
@@ -104,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 */
 
 
@@ -124,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))
@@ -135,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
 
 
@@ -222,20 +256,22 @@ _hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size)
 typedef int (*hb_compare_func_t) (const void *, const void *);
 
 
-HB_END_DECLS
 
 
 /* arrays and maps */
 
 
+#define HB_PREALLOCED_ARRAY_INIT {0}
 template <typename Type, unsigned int StaticSize>
-struct hb_prealloced_array_t {
-
+struct hb_prealloced_array_t
+{
   unsigned int len;
   unsigned int allocated;
   Type *array;
   Type static_array[StaticSize];
 
+  void init (void) { memset (this, 0, sizeof (*this)); }
+
   inline Type& operator [] (unsigned int i) { return array[i]; }
   inline const Type& operator [] (unsigned int i) const { return array[i]; }
 
@@ -329,25 +365,31 @@ struct hb_prealloced_array_t {
   }
 };
 
-template <typename Type>
-struct hb_array_t : hb_prealloced_array_t<Type, 2> {};
-
 
+#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
 template <typename item_t, typename lock_t>
 struct hb_lockable_set_t
 {
-  hb_array_t <item_t> items;
+  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)
+  inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
   {
     l.lock ();
     item_t *item = items.find (v);
     if (item) {
-      item_t old = *item;
-      *item = v;
-      l.unlock ();
-      old.finish ();
+      if (replace) {
+       item_t old = *item;
+       *item = v;
+       l.unlock ();
+       old.finish ();
+      }
+      else {
+        item = NULL;
+       l.unlock ();
+      }
     } else {
       item = items.push ();
       if (likely (item))
@@ -415,7 +457,6 @@ struct hb_lockable_set_t
 };
 
 
-HB_BEGIN_DECLS
 
 
 /* Big-endian handling */
@@ -426,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])
@@ -462,28 +511,198 @@ static inline unsigned char TOLOWER (unsigned char c)
 
 /* 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.
  */
-static inline bool
-hb_codepoint_in_range (hb_codepoint_t u, hb_codepoint_t lo, hb_codepoint_t hi)
+template <typename T> inline bool
+hb_in_range (T u, T lo, T hi)
 {
   if ( ((lo^hi) & lo) == 0 &&
        ((lo^hi) & hi) == (lo^hi) &&
@@ -494,9 +713,37 @@ hb_codepoint_in_range (hb_codepoint_t u, hb_codepoint_t lo, hb_codepoint_t hi)
 }
 
 
-/* Useful for set-operations on small enums */
+/* 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))
 
-HB_END_DECLS
+
+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);
+}
+
+
+
 
 #endif /* HB_PRIVATE_HH */