X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fhb-private.hh;h=0cb049e8d053d5cd32552e45eb7c01dae26f7ed5;hb=HEAD;hp=b5745e74fb66ab4ecd3239f1021bd246c07aa96e;hpb=7b08b0a7f2057937dfc3ab2ec191656bf2386463;p=framework%2Fuifw%2Fharfbuzz.git diff --git a/src/hb-private.hh b/src/hb-private.hh index b5745e7..0cb049e 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -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. * @@ -29,13 +29,19 @@ #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 +#include #include #include @@ -45,8 +51,8 @@ * someway around that. */ #include #include +#include -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 static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; } @@ -72,7 +71,6 @@ template static inline Type MIN (const Type &a, const Type &b) { #undef MAX template 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 -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 -struct hb_array_t : hb_prealloced_array_t {}; - +#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT} template struct hb_lockable_set_t { - hb_array_t items; + hb_prealloced_array_t items; + + inline void init (void) { items.init (); } template - 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 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 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 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 (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 (#WHAT, (OBJ), NULL, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__) +#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg (#WHAT, (OBJ), NULL, false, 0, 0, __VA_ARGS__) +#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__) + + +/* + * Trace + */ + +template +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 (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 (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 (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 + 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 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 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 */