Add initial implementation of user_data to objects
authorBehdad Esfahbod <behdad@behdad.org>
Thu, 28 Apr 2011 01:22:32 +0000 (21:22 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Thu, 28 Apr 2011 01:27:40 +0000 (21:27 -0400)
src/hb-common.h
src/hb-object-private.hh

index e6f5f2b..74030f4 100644 (file)
@@ -68,8 +68,6 @@ typedef union _hb_var_int_t {
   int8_t i8[4];
 } hb_var_int_t;
 
-typedef void (*hb_destroy_func_t) (void *user_data);
-
 
 /* hb_tag_t */
 
@@ -287,6 +285,15 @@ hb_direction_t
 hb_script_get_horizontal_direction (hb_script_t script);
 
 
+/* User data */
+
+typedef struct _hb_user_data_key_t {
+  char unused;
+} hb_user_data_key_t;
+
+typedef void (*hb_destroy_func_t) (void *user_data);
+
+
 HB_END_DECLS
 
 #endif /* HB_COMMON_H */
index 8fbddd4..7bc6b46 100644 (file)
@@ -44,10 +44,172 @@ HB_BEGIN_DECLS
 #endif
 
 
+/* user_data */
+
+HB_END_DECLS
+
+
+template <typename Type, unsigned int StaticSize>
+struct hb_static_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 *push (void)
+  {
+    if (!array) {
+      array = static_array;
+      allocated = ARRAY_LENGTH (static_array);
+    }
+    if (likely (len < allocated))
+      return &array[len++];
+    /* Need to reallocate */
+    unsigned int new_allocated = allocated + (allocated >> 1) + 8;
+    Type *new_array;
+    if (array == static_array) {
+      new_array = (Type *) calloc (new_allocated, sizeof (Type));
+      if (new_array) {
+        memcpy (new_array, array, len * sizeof (Type));
+       array = new_array;
+      }
+    } else {
+      bool overflows = new_allocated >= ((unsigned int) -1) / sizeof (Type);
+      if (unlikely (overflows))
+        new_array = NULL;
+      else
+       new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
+      if (new_array) {
+        free (array);
+       array = new_array;
+      }
+    }
+    if ((len < allocated))
+      return &array[len++];
+    else
+      return NULL;
+  }
+
+  inline void pop (void)
+  {
+    len--;
+    /* TODO: shrink array if needed */
+  }
+};
+
+template <typename Type>
+struct hb_array_t : hb_static_array_t<Type, 2> {};
+
+
+template <typename Key, typename Value>
+struct hb_map_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;
+  }
+
+  public:
+
+  inline bool set (Key   key,
+                  Value &value)
+  {
+    if (unlikely (!key)) return NULL;
+    item_t *item;
+    item = find (key);
+    if (item)
+      item->finish ();
+    else
+      item = items.push ();
+    if (unlikely (!item)) return false;
+    item->key = key;
+    item->value = value;
+    return true;
+  }
+
+  inline void unset (Key &key)
+  {
+    item_t *item;
+    item = find (key);
+    if (!item) return;
+
+    item->finish ();
+    items[items.len - 1] = *item;
+    items.pop ();
+  }
+
+  inline Value *get (Key key)
+  {
+    item_t *item = find (key);
+    return item ? &item->value : NULL;
+  }
+
+  void finish (void) { items.finish (); }
+};
+
+
+HB_BEGIN_DECLS
+
+typedef struct {
+  void *data;
+  hb_destroy_func_t destroy;
+
+  void finish (void) { if (destroy) destroy (data); }
+} hb_user_data_t;
+
+struct hb_user_data_array_t {
+
+  hb_map_t<hb_user_data_key_t *, hb_user_data_t> map;
+
+  inline bool set (hb_user_data_key_t *key,
+                  void *              data,
+                  hb_destroy_func_t   destroy)
+  {
+    if (!data && !destroy) {
+      map.unset (key);
+      return true;
+    }
+    hb_user_data_t user_data = {data, destroy};
+    return map.set (key, user_data);
+  }
+
+  inline void *get (hb_user_data_key_t *key) {
+    return map.get (key);
+  }
+
+  void finish (void) { map.finish (); }
+};
+
+
+
 typedef struct _hb_object_header_t hb_object_header_t;
 
 struct _hb_object_header_t {
   hb_reference_count_t ref_count;
+  hb_user_data_array_t user_data;
 
 #define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID}
 
@@ -64,7 +226,9 @@ struct _hb_object_header_t {
     ref_count.init (1);
   }
 
-  inline bool is_inert (void) const { return unlikely (ref_count.is_invalid ()); }
+  inline bool is_inert (void) const {
+    return unlikely (ref_count.is_invalid ());
+  }
 
   inline void reference (void) {
     if (unlikely (!this || this->is_inert ()))
@@ -75,7 +239,25 @@ struct _hb_object_header_t {
   inline bool destroy (void) {
     if (unlikely (!this || this->is_inert ()))
       return false;
-    return ref_count.dec () == 1;
+    if (ref_count.dec () != 1)
+      return false;
+
+    user_data.finish ();
+
+    return true;
+  }
+
+  inline bool set_user_data (hb_user_data_key_t *key,
+                            void *              data,
+                            hb_destroy_func_t   destroy) {
+    if (unlikely (!this || this->is_inert ()))
+      return false;
+
+    return user_data.set (key, data, destroy);
+  }
+
+  inline void *get_user_data (hb_user_data_key_t *key) {
+    return user_data.get (key);
   }
 
   inline void trace (const char *function) const {