#include "hb-common.h"
#include <stdlib.h>
+#include <stddef.h>
#include <string.h>
#include <assert.h>
* someway around that. */
#include <stdio.h>
#include <errno.h>
+#include <stdarg.h>
HB_BEGIN_DECLS
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
#define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1]))
+#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
/* Lets assert int types. Saves trouble down the road. */
#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_FUCN(format_idx, arg_idx)
#endif
#if __GNUC__ >= 4
#define HB_UNUSED __attribute__((unused))
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))
-#define hb_mutex_free(M) g_static_mutex_free (&(M))
-
-#else
-
-#ifdef _MSC_VER
-
-#include <intrin.h>
-
-typedef long hb_atomic_int_t;
-#define hb_atomic_int_fetch_and_add(AI, V) _InterlockedExchangeAdd (&(AI), V)
-#define hb_atomic_int_get(AI) (_ReadBarrier (), (AI))
-#define hb_atomic_int_set(AI, V) ((void) _InterlockedExchange (&(AI), (V)))
-
-typedef void * hb_mutex_t;
-extern HB_INTERNAL hb_mutex_t _hb_win32_mutex_create (void);
-extern HB_INTERNAL void _hb_win32_mutex_init (hb_mutex_t *m);
-extern HB_INTERNAL void _hb_win32_mutex_lock (hb_mutex_t m);
-extern HB_INTERNAL int _hb_win32_mutex_trylock (hb_mutex_t m);
-extern HB_INTERNAL void _hb_win32_mutex_unlock (hb_mutex_t m);
-extern HB_INTERNAL void _hb_win32_mutex_free (hb_mutex_t *m);
-#define HB_MUTEX_INIT _hb_win32_mutex_create ()
-#define hb_mutex_init(M) _hb_win32_mutex_init (&(M))
-#define hb_mutex_lock(M) _hb_win32_mutex_lock ((M))
-#define hb_mutex_trylock(M) _hb_win32_mutex_trylock ((M))
-#define hb_mutex_unlock(M) _hb_win32_mutex_unlock ((M))
-#define hb_mutex_free(M) _hb_win32_mutex_free (&(M))
-
-#else
-
-#warning "Could not find any system to define platform macros, library will NOT be thread-safe"
-
-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) ((void) ((AI) = (V)))
-
-typedef volatile int hb_mutex_t;
-#define HB_MUTEX_INIT 0
-#define hb_mutex_init(M) ((void) ((M) = 0))
-#define hb_mutex_lock(M) ((void) ((M) = 1))
-#define hb_mutex_trylock(M) ((M) = 1, 1)
-#define hb_mutex_unlock(M) ((void) ((M) = 0))
-#define hb_mutex_free(M) ((void) ((M) = 2))
-
-#endif
-
-#endif
-
-
HB_END_DECLS
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 (); }
-
- 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)
{
len--;
/* TODO: shrink array if needed */
}
+
+ inline void shrink (unsigned int l)
+ {
+ if (l < len)
+ len = l;
+ /* TODO: shrink array if needed */
+ }
+
+ 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;
+ }
+
+ inline void sort (void)
+ {
+ qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+ }
+
+ inline void sort (unsigned int start, unsigned int end)
+ {
+ qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
+ }
+
+ 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 void finish (void)
+ {
+ if (array != static_array)
+ free (array);
+ array = NULL;
+ allocated = len = 0;
+ }
};
template <typename Type>
-struct hb_array_t : hb_static_array_t<Type, 2> {};
+struct hb_array_t : hb_prealloced_array_t<Type, 2> {};
-template <typename Key, typename Value>
-struct hb_map_t
+template <typename item_t, typename lock_t>
+struct hb_lockable_set_t
{
- struct item_t {
- Key key;
- /* unsigned int hash; */
- Value value;
-
- void finish (void) { value.finish (); }
- };
-
hb_array_t <item_t> items;
- private:
-
- 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;
+ template <typename T>
+ inline item_t *replace_or_insert (T v, lock_t &l)
+ {
+ l.lock ();
+ item_t *item = items.find (v);
+ if (item) {
+ item_t old = *item;
+ *item = v;
+ l.unlock ();
+ old.finish ();
+ } else {
+ item = items.push ();
+ if (likely (item))
+ *item = v;
+ l.unlock ();
+ }
+ return item;
}
- public:
+ template <typename T>
+ inline void remove (T v, lock_t &l)
+ {
+ 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 ();
+ }
+ }
- inline bool set (Key key,
- Value &value)
+ template <typename T>
+ inline bool find (T v, item_t *i, lock_t &l)
{
- if (unlikely (!key)) return NULL;
- item_t *item;
- item = find (key);
+ l.lock ();
+ item_t *item = items.find (v);
if (item)
- item->finish ();
- else
- item = items.push ();
- if (unlikely (!item)) return false;
- item->key = key;
- item->value = value;
- return true;
+ *i = *item;
+ l.unlock ();
+ return !!item;
}
- inline void unset (Key &key)
+ template <typename T>
+ inline item_t *find_or_insert (T v, lock_t &l)
{
- item_t *item;
- item = find (key);
- if (!item) return;
-
- item->finish ();
- *item = items[items.len - 1];
- items.pop ();
+ l.lock ();
+ item_t *item = items.find (v);
+ if (!item) {
+ item = items.push ();
+ if (likely (item))
+ *item = v;
+ }
+ l.unlock ();
+ return item;
}
- inline Value *get (Key key)
+ inline void finish (lock_t &l)
{
- item_t *item = find (key);
- return item ? &item->value : NULL;
+ 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 (); }
};
((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 */
+HB_END_DECLS
+
#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 bool /* always returns TRUE */
+_hb_debug_msg (const char *what,
+ const void *obj,
+ const char *func,
+ bool indented,
+ int level,
+ const char *message,
+ ...) HB_PRINTF_FUNC(6, 7);
+template <int max_level> inline bool /* always returns TRUE */
+_hb_debug_msg (const char *what,
+ const void *obj,
+ const char *func,
+ bool indented,
+ int level,
+ const char *message,
+ ...)
+{
+ va_list ap;
+ va_start (ap, message);
+
+ (void) (_hb_debug (level, max_level) &&
+ fprintf (stderr, "%s(%p): ", what, obj) &&
+ (func && fprintf (stderr, "%s: ", func), TRUE) &&
+ (indented && fprintf (stderr, "%-*d-> ", level + 1, level), TRUE) &&
+ vfprintf (stderr, message, ap) &&
+ fprintf (stderr, "\n"));
+
+ va_end (ap);
+
+ return TRUE;
+}
+template <> inline bool /* always returns TRUE */
+_hb_debug_msg<0> (const char *what,
+ const void *obj,
+ const char *func,
+ bool indented,
+ int level,
+ const char *message,
+ ...) HB_PRINTF_FUNC(6, 7);
+template <> inline bool /* always returns TRUE */
+_hb_debug_msg<0> (const char *what,
+ const void *obj,
+ const char *func,
+ bool indented,
+ int level,
+ const char *message,
+ ...)
{
- (void) ((depth < max_depth) && fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, depth, depth, function));
return TRUE;
}
+#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, FALSE, (LEVEL), __VA_ARGS__)
+#define DEBUG_MSG(WHAT, OBJ, ...) DEBUG_MSG_LEVEL (WHAT, OBJ, 0, __VA_ARGS__)
+#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, FALSE, 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_)
+ {
+ if (max_level) ++*plevel;
+ /* TODO support variadic args here */
+ _hb_debug_msg<max_level> (what, obj, func, TRUE, *plevel, "%s", message);
+ }
+ ~hb_auto_trace_t (void) { if (max_level) --*plevel; }
+
+ private:
+ unsigned int *plevel;
+};
+template <> /* Optimize when tracing is disabled */
+struct hb_auto_trace_t<0> {
+ explicit inline hb_auto_trace_t (unsigned int *plevel_,
+ const char *what,
+ const void *obj,
+ const char *func,
+ const char *message) {}
+};
+
+
+/* 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_BEGIN_DECLS
HB_END_DECLS