Imported Upstream version 2.6.7
[platform/upstream/harfbuzz.git] / src / hb-serialize.hh
index 4c674b1..4fb4f4e 100644 (file)
@@ -45,12 +45,13 @@ struct hb_serialize_context_t
 {
   typedef unsigned objidx_t;
 
-  struct range_t
-  {
-    char *head, *tail;
-  };
+  enum whence_t {
+     Head,     /* Relative to the current object head (default). */
+     Tail,     /* Relative to the current object tail after packed. */
+     Absolute  /* Absolute: from the start of the serialize buffer. */
+   };
 
-  struct object_t : range_t
+  struct object_t
   {
     void fini () { links.fini (); }
 
@@ -70,17 +71,29 @@ struct hb_serialize_context_t
     struct link_t
     {
       bool is_wide: 1;
-      unsigned position : 31;
+      bool is_signed: 1;
+      unsigned whence: 2;
+      unsigned position: 28;
       unsigned bias;
       objidx_t objidx;
     };
 
+    char *head;
+    char *tail;
     hb_vector_t<link_t> links;
     object_t *next;
   };
 
-  range_t snapshot () { range_t s = {head, tail} ; return s; }
+  struct snapshot_t
+  {
+    char *head;
+    char *tail;
+    object_t *current; // Just for sanity check
+    unsigned num_links;
+  };
 
+  snapshot_t snapshot ()
+  { return snapshot_t { head, tail, current, current->links.length }; }
 
   hb_serialize_context_t (void *start_, unsigned int size) :
     start ((char *) start_),
@@ -123,7 +136,7 @@ struct hb_serialize_context_t
 
   template <typename T1, typename T2>
   bool check_equal (T1 &&v1, T2 &&v2)
-  { return check_success (v1 == v2); }
+  { return check_success ((long long) v1 == (long long) v2); }
 
   template <typename T1, typename T2>
   bool check_assign (T1 &v1, T2 &&v2)
@@ -166,7 +179,7 @@ struct hb_serialize_context_t
     if (packed.length <= 1)
       return;
 
-    pop_pack ();
+    pop_pack (false);
 
     resolve_links ();
   }
@@ -191,11 +204,16 @@ struct hb_serialize_context_t
     object_t *obj = current;
     if (unlikely (!obj)) return;
     current = current->next;
-    revert (*obj);
+    revert (obj->head, obj->tail);
     obj->fini ();
     object_pool.free (obj);
   }
-  objidx_t pop_pack ()
+
+  /* Set share to false when an object is unlikely sharable with others
+   * so not worth an attempt, or a contiguous table is serialized as
+   * multiple consecutive objects in the reverse order so can't be shared.
+   */
+  objidx_t pop_pack (bool share=true)
   {
     object_t *obj = current;
     if (unlikely (!obj)) return 0;
@@ -211,11 +229,15 @@ struct hb_serialize_context_t
       return 0;
     }
 
-    objidx_t objidx = packed_map.get (obj);
-    if (objidx)
+    objidx_t objidx;
+    if (share)
     {
-      obj->fini ();
-      return objidx;
+      objidx = packed_map.get (obj);
+      if (objidx)
+      {
+       obj->fini ();
+       return objidx;
+      }
     }
 
     tail -= len;
@@ -231,17 +253,24 @@ struct hb_serialize_context_t
 
     objidx = packed.length - 1;
 
-    packed_map.set (obj, objidx);
+    if (share) packed_map.set (obj, objidx);
 
     return objidx;
   }
 
-  void revert (range_t snap)
+  void revert (snapshot_t snap)
+  {
+    assert (snap.current == current);
+    current->links.shrink (snap.num_links);
+    revert (snap.head, snap.tail);
+  }
+  void revert (char *snap_head,
+              char *snap_tail)
   {
-    assert (snap.head <= head);
-    assert (tail <= snap.tail);
-    head = snap.head;
-    tail = snap.tail;
+    assert (snap_head <= head);
+    assert (tail <= snap_tail);
+    head = snap_head;
+    tail = snap_tail;
     discard_stale_objects ();
   }
 
@@ -260,7 +289,9 @@ struct hb_serialize_context_t
   }
 
   template <typename T>
-  void add_link (T &ofs, objidx_t objidx, const void *base = nullptr)
+  void add_link (T &ofs, objidx_t objidx,
+                whence_t whence = Head,
+                unsigned bias = 0)
   {
     static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");
 
@@ -270,18 +301,24 @@ struct hb_serialize_context_t
     assert (current);
     assert (current->head <= (const char *) &ofs);
 
-    if (!base)
-      base = current->head;
-    else
-      assert (current->head <= (const char *) base);
-
     auto& link = *current->links.push ();
+
     link.is_wide = sizeof (T) == 4;
+    link.is_signed = hb_is_signed (hb_unwrap_type (T));
+    link.whence = (unsigned) whence;
     link.position = (const char *) &ofs - current->head;
-    link.bias = (const char *) base - current->head;
+    link.bias = bias;
     link.objidx = objidx;
   }
 
+  unsigned to_bias (const void *base) const
+  {
+    if (!base) return 0;
+    assert (current);
+    assert (current->head <= (const char *) base);
+    return (const char *) base - current->head;
+  }
+
   void resolve_links ()
   {
     if (unlikely (in_error ())) return;
@@ -293,20 +330,29 @@ struct hb_serialize_context_t
       for (const object_t::link_t &link : parent->links)
       {
        const object_t* child = packed[link.objidx];
-       assert (link.bias <= (size_t) (parent->tail - parent->head));
-       unsigned offset = (child->head - parent->head) - link.bias;
+       if (unlikely (!child)) { err_other_error(); return; }
+       unsigned offset = 0;
+       switch ((whence_t) link.whence) {
+       case Head:     offset = child->head - parent->head; break;
+       case Tail:     offset = child->head - parent->tail; break;
+       case Absolute: offset = (head - start) + (child->head - tail); break;
+       }
 
-       if (link.is_wide)
+       assert (offset >= link.bias);
+       offset -= link.bias;
+       if (link.is_signed)
        {
-         auto &off = * ((BEInt<uint32_t, 4> *) (parent->head + link.position));
-         assert (0 == off);
-         check_assign (off, offset);
+         if (link.is_wide)
+           assign_offset<int32_t> (parent, link, offset);
+         else
+           assign_offset<int16_t> (parent, link, offset);
        }
        else
        {
-         auto &off = * ((BEInt<uint16_t, 2> *) (parent->head + link.position));
-         assert (0 == off);
-         check_assign (off, offset);
+         if (link.is_wide)
+           assign_offset<uint32_t> (parent, link, offset);
+         else
+           assign_offset<uint16_t> (parent, link, offset);
        }
       }
   }
@@ -387,6 +433,12 @@ struct hb_serialize_context_t
   Type *copy (const Type *src, Ts&&... ds)
   { return copy (*src, hb_forward<Ts> (ds)...); }
 
+  template<typename Iterator,
+          hb_requires (hb_is_iterator (Iterator)),
+          typename ...Ts>
+  void copy_all (Iterator it, Ts&&... ds)
+  { for (decltype (*it) _ : it) copy (_, hb_forward<Ts> (ds)...); }
+
   template <typename Type>
   hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
 
@@ -441,6 +493,15 @@ struct hb_serialize_context_t
                           (char *) b.arrayZ, free);
   }
 
+  private:
+  template <typename T>
+  void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
+  {
+    auto &off = * ((BEInt<T, sizeof (T)> *) (parent->head + link.position));
+    assert (0 == off);
+    check_assign (off, offset);
+  }
+
   public: /* TODO Make private. */
   char *start, *head, *tail, *end;
   unsigned int debug_depth;