• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2012,2018  Google, Inc.
4  * Copyright © 2019  Facebook, Inc.
5  *
6  *  This is part of HarfBuzz, a text shaping library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Red Hat Author(s): Behdad Esfahbod
27  * Google Author(s): Behdad Esfahbod
28  * Facebook Author(s): Behdad Esfahbod
29  */
30 
31 #ifndef HB_SERIALIZE_HH
32 #define HB_SERIALIZE_HH
33 
34 #include "hb.hh"
35 #include "hb-blob.hh"
36 #include "hb-map.hh"
37 #include "hb-pool.hh"
38 
39 #include "hb-subset-serialize.h"
40 
41 /*
42  * Serialize
43  */
44 
45 enum hb_serialize_error_t {
46   HB_SERIALIZE_ERROR_NONE =            0x00000000u,
47   HB_SERIALIZE_ERROR_OTHER =           0x00000001u,
48   HB_SERIALIZE_ERROR_OFFSET_OVERFLOW = 0x00000002u,
49   HB_SERIALIZE_ERROR_OUT_OF_ROOM =     0x00000004u,
50   HB_SERIALIZE_ERROR_INT_OVERFLOW =    0x00000008u,
51   HB_SERIALIZE_ERROR_ARRAY_OVERFLOW =  0x00000010u
52 };
53 HB_MARK_AS_FLAG_T (hb_serialize_error_t);
54 
55 struct hb_serialize_context_t
56 {
57   typedef unsigned objidx_t;
58 
59   enum whence_t {
60      Head,	/* Relative to the current object head (default). */
61      Tail,	/* Relative to the current object tail after packed. */
62      Absolute	/* Absolute: from the start of the serialize buffer. */
63    };
64 
65 
66 
67   struct object_t
68   {
finihb_serialize_context_t::object_t69     void fini () {
70       real_links.fini ();
71       virtual_links.fini ();
72     }
73 
74     object_t () = default;
75 
object_thb_serialize_context_t::object_t76     object_t (const hb_subset_serialize_object_t &o)
77     {
78       head = o.head;
79       tail = o.tail;
80       next = nullptr;
81       real_links.alloc (o.num_real_links, true);
82       for (unsigned i = 0 ; i < o.num_real_links; i++)
83         real_links.push (o.real_links[i]);
84 
85       virtual_links.alloc (o.num_virtual_links, true);
86       for (unsigned i = 0; i < o.num_virtual_links; i++)
87         virtual_links.push (o.virtual_links[i]);
88     }
89 
add_virtual_linkhb_serialize_context_t::object_t90     bool add_virtual_link (objidx_t objidx)
91     {
92       if (!objidx)
93         return false;
94 
95       auto& link = *virtual_links.push ();
96       if (virtual_links.in_error ())
97         return false;
98 
99       link.objidx = objidx;
100       // Remaining fields were previously zero'd by push():
101       // link.width = 0;
102       // link.is_signed = 0;
103       // link.whence = 0;
104       // link.position = 0;
105       // link.bias = 0;
106 
107       return true;
108     }
109 
swaphb_serialize_context_t110     friend void swap (object_t& a, object_t& b) noexcept
111     {
112       hb_swap (a.head, b.head);
113       hb_swap (a.tail, b.tail);
114       hb_swap (a.next, b.next);
115       hb_swap (a.real_links, b.real_links);
116       hb_swap (a.virtual_links, b.virtual_links);
117     }
118 
operator ==hb_serialize_context_t::object_t119     bool operator == (const object_t &o) const
120     {
121       // Virtual links aren't considered for equality since they don't affect the functionality
122       // of the object.
123       return (tail - head == o.tail - o.head)
124 	  && (real_links.length == o.real_links.length)
125 	  && 0 == hb_memcmp (head, o.head, tail - head)
126 	  && real_links.as_bytes () == o.real_links.as_bytes ();
127     }
hashhb_serialize_context_t::object_t128     uint32_t hash () const
129     {
130       // Virtual links aren't considered for equality since they don't affect the functionality
131       // of the object.
132       return hb_bytes_t (head, hb_min (128, tail - head)).hash () ^
133           real_links.as_bytes ().hash ();
134     }
135 
136     struct link_t
137     {
138       unsigned width: 3;
139       unsigned is_signed: 1;
140       unsigned whence: 2;
141       unsigned bias : 26;
142       unsigned position;
143       objidx_t objidx;
144 
145       link_t () = default;
146 
link_thb_serialize_context_t::object_t::link_t147       link_t (const hb_subset_serialize_link_t &o)
148       {
149         width = o.width;
150         is_signed = 0;
151         whence = 0;
152         position = o.position;
153         bias = 0;
154         objidx = o.objidx;
155       }
156 
cmphb_serialize_context_t::object_t::link_t157       HB_INTERNAL static int cmp (const void* a, const void* b)
158       {
159         int cmp = ((const link_t*)a)->position - ((const link_t*)b)->position;
160         if (cmp) return cmp;
161 
162         return ((const link_t*)a)->objidx - ((const link_t*)b)->objidx;
163       }
164     };
165 
166     char *head;
167     char *tail;
168     hb_vector_t<link_t> real_links;
169     hb_vector_t<link_t> virtual_links;
170     object_t *next;
171 
172     auto all_links () const HB_AUTO_RETURN
173         (( hb_concat (real_links, virtual_links) ));
174     auto all_links_writer () HB_AUTO_RETURN
175         (( hb_concat (real_links.writer (), virtual_links.writer ()) ));
176   };
177 
178   struct snapshot_t
179   {
180     char *head;
181     char *tail;
182     object_t *current; // Just for sanity check
183     unsigned num_real_links;
184     unsigned num_virtual_links;
185     hb_serialize_error_t errors;
186   };
187 
snapshothb_serialize_context_t188   snapshot_t snapshot ()
189   {
190     return snapshot_t {
191       head, tail, current,
192       current ? current->real_links.length : 0,
193       current ? current->virtual_links.length : 0,
194       errors
195      };
196   }
197 
hb_serialize_context_thb_serialize_context_t198   hb_serialize_context_t (void *start_, unsigned int size) :
199     start ((char *) start_),
200     end (start + size),
201     current (nullptr)
202   { reset (); }
~hb_serialize_context_thb_serialize_context_t203   ~hb_serialize_context_t () { fini (); }
204 
finihb_serialize_context_t205   void fini ()
206   {
207     for (object_t *_ : ++hb_iter (packed)) _->fini ();
208     packed.fini ();
209     this->packed_map.fini ();
210 
211     while (current)
212     {
213       auto *_ = current;
214       current = current->next;
215       _->fini ();
216     }
217   }
218 
in_errorhb_serialize_context_t219   bool in_error () const { return bool (errors); }
220 
successfulhb_serialize_context_t221   bool successful () const { return !bool (errors); }
222 
ran_out_of_roomhb_serialize_context_t223   HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; }
offset_overflowhb_serialize_context_t224   HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
only_offset_overflowhb_serialize_context_t225   HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; }
only_overflowhb_serialize_context_t226   HB_NODISCARD bool only_overflow () const
227   {
228     return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW
229         || errors == HB_SERIALIZE_ERROR_INT_OVERFLOW
230         || errors == HB_SERIALIZE_ERROR_ARRAY_OVERFLOW;
231   }
232 
resethb_serialize_context_t233   void reset (void *start_, unsigned int size)
234   {
235     start = (char*) start_;
236     end = start + size;
237     reset ();
238     current = nullptr;
239   }
240 
resethb_serialize_context_t241   void reset ()
242   {
243     this->errors = HB_SERIALIZE_ERROR_NONE;
244     this->head = this->start;
245     this->tail = this->end;
246     this->zerocopy = nullptr;
247     this->debug_depth = 0;
248 
249     fini ();
250     this->packed.push (nullptr);
251     this->packed_map.init ();
252   }
253 
check_successhb_serialize_context_t254   bool check_success (bool success,
255                       hb_serialize_error_t err_type = HB_SERIALIZE_ERROR_OTHER)
256   {
257     return successful ()
258         && (success || err (err_type));
259   }
260 
261   template <typename T1, typename T2>
check_equalhb_serialize_context_t262   bool check_equal (T1 &&v1, T2 &&v2, hb_serialize_error_t err_type)
263   {
264     if ((long long) v1 != (long long) v2)
265     {
266       return err (err_type);
267     }
268     return true;
269   }
270 
271   template <typename T1, typename T2>
check_assignhb_serialize_context_t272   bool check_assign (T1 &v1, T2 &&v2, hb_serialize_error_t err_type)
273   { return check_equal (v1 = v2, v2, err_type); }
274 
propagate_errorhb_serialize_context_t275   template <typename T> bool propagate_error (T &&obj)
276   { return check_success (!hb_deref (obj).in_error ()); }
277 
propagate_errorhb_serialize_context_t278   template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os)
279   { return propagate_error (std::forward<T1> (o1)) &&
280 	   propagate_error (std::forward<Ts> (os)...); }
281 
282   /* To be called around main operation. */
283   template <typename Type=char>
284   __attribute__((returns_nonnull))
start_serializehb_serialize_context_t285   Type *start_serialize ()
286   {
287     DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
288 		     "start [%p..%p] (%lu bytes)",
289 		     this->start, this->end,
290 		     (unsigned long) (this->end - this->start));
291 
292     assert (!current);
293     return push<Type> ();
294   }
end_serializehb_serialize_context_t295   void end_serialize ()
296   {
297     DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
298 		     "end [%p..%p] serialized %u bytes; %s",
299 		     this->start, this->end,
300 		     (unsigned) (this->head - this->start),
301 		     successful () ? "successful" : "UNSUCCESSFUL");
302 
303     propagate_error (packed, packed_map);
304 
305     if (unlikely (!current)) return;
306     if (unlikely (in_error()))
307     {
308       // Offset overflows that occur before link resolution cannot be handled
309       // by repacking, so set a more general error.
310       if (offset_overflow ()) err (HB_SERIALIZE_ERROR_OTHER);
311       return;
312     }
313 
314     assert (!current->next);
315 
316     /* Only "pack" if there exist other objects... Otherwise, don't bother.
317      * Saves a move. */
318     if (packed.length <= 1)
319       return;
320 
321     pop_pack (false);
322 
323     resolve_links ();
324   }
325 
326   template <typename Type = void>
327   __attribute__((returns_nonnull))
pushhb_serialize_context_t328   Type *push ()
329   {
330     if (unlikely (in_error ())) return start_embed<Type> ();
331 
332     object_t *obj = object_pool.alloc ();
333     if (unlikely (!obj))
334       check_success (false);
335     else
336     {
337       obj->head = head;
338       obj->tail = tail;
339       obj->next = current;
340       current = obj;
341     }
342     return start_embed<Type> ();
343   }
pop_discardhb_serialize_context_t344   void pop_discard ()
345   {
346     object_t *obj = current;
347     if (unlikely (!obj)) return;
348     // Allow cleanup when we've error'd out on int overflows which don't compromise
349     // the serializer state.
350     if (unlikely (in_error() && !only_overflow ())) return;
351 
352     current = current->next;
353     revert (zerocopy ? zerocopy : obj->head, obj->tail);
354     zerocopy = nullptr;
355     obj->fini ();
356     object_pool.release (obj);
357   }
358 
359   /* Set share to false when an object is unlikely shareable with others
360    * so not worth an attempt, or a contiguous table is serialized as
361    * multiple consecutive objects in the reverse order so can't be shared.
362    */
pop_packhb_serialize_context_t363   objidx_t pop_pack (bool share=true)
364   {
365     object_t *obj = current;
366     if (unlikely (!obj)) return 0;
367     // Allow cleanup when we've error'd out on int overflows which don't compromise
368     // the serializer state.
369     if (unlikely (in_error()  && !only_overflow ())) return 0;
370 
371     current = current->next;
372     obj->tail = head;
373     obj->next = nullptr;
374     assert (obj->head <= obj->tail);
375     unsigned len = obj->tail - obj->head;
376     head = zerocopy ? zerocopy : obj->head; /* Rewind head. */
377     bool was_zerocopy = zerocopy;
378     zerocopy = nullptr;
379 
380     if (!len)
381     {
382       assert (!obj->real_links.length);
383       assert (!obj->virtual_links.length);
384       return 0;
385     }
386 
387     objidx_t objidx;
388     uint32_t hash = 0;
389     if (share)
390     {
391       hash = hb_hash (obj);
392       objidx = packed_map.get_with_hash (obj, hash);
393       if (objidx)
394       {
395         merge_virtual_links (obj, objidx);
396 	obj->fini ();
397         object_pool.release (obj);
398 	return objidx;
399       }
400     }
401 
402     tail -= len;
403     if (was_zerocopy)
404       assert (tail == obj->head);
405     else
406       memmove (tail, obj->head, len);
407 
408     obj->head = tail;
409     obj->tail = tail + len;
410 
411     packed.push (obj);
412 
413     if (unlikely (!propagate_error (packed)))
414     {
415       /* Obj wasn't successfully added to packed, so clean it up otherwise its
416        * links will be leaked. When we use constructor/destructors properly, we
417        * can remove these. */
418       obj->fini ();
419       return 0;
420     }
421 
422     objidx = packed.length - 1;
423 
424     if (share) packed_map.set_with_hash (obj, hash, objidx);
425     propagate_error (packed_map);
426 
427     return objidx;
428   }
429 
reverthb_serialize_context_t430   void revert (snapshot_t snap)
431   {
432     // Overflows that happened after the snapshot will be erased by the revert.
433     if (unlikely (in_error () && !only_overflow ())) return;
434     assert (snap.current == current);
435     if (current)
436     {
437       current->real_links.shrink (snap.num_real_links);
438       current->virtual_links.shrink (snap.num_virtual_links);
439     }
440     errors = snap.errors;
441     revert (snap.head, snap.tail);
442   }
443 
reverthb_serialize_context_t444   void revert (char *snap_head,
445 	       char *snap_tail)
446   {
447     if (unlikely (in_error ())) return;
448     assert (snap_head <= head);
449     assert (tail <= snap_tail);
450     head = snap_head;
451     tail = snap_tail;
452     discard_stale_objects ();
453   }
454 
discard_stale_objectshb_serialize_context_t455   void discard_stale_objects ()
456   {
457     if (unlikely (in_error ())) return;
458     while (packed.length > 1 &&
459 	   packed.tail ()->head < tail)
460     {
461       object_t *obj = packed.tail ();
462       packed_map.del (obj);
463       assert (!obj->next);
464       obj->fini ();
465       object_pool.release (obj);
466       packed.pop ();
467     }
468     if (packed.length > 1)
469       assert (packed.tail ()->head == tail);
470   }
471 
472   // Adds a virtual link from the current object to objidx. A virtual link is not associated with
473   // an actual offset field. They are solely used to enforce ordering constraints between objects.
474   // Adding a virtual link from object a to object b will ensure that object b is always packed after
475   // object a in the final serialized order.
476   //
477   // This is useful in certain situations where there needs to be a specific ordering in the
478   // final serialization. Such as when platform bugs require certain orderings, or to provide
479   //  guidance to the repacker for better offset overflow resolution.
add_virtual_linkhb_serialize_context_t480   void add_virtual_link (objidx_t objidx)
481   {
482     if (unlikely (in_error ())) return;
483 
484     if (!objidx)
485       return;
486 
487     assert (current);
488 
489     if (!current->add_virtual_link(objidx))
490       err (HB_SERIALIZE_ERROR_OTHER);
491   }
492 
last_added_child_indexhb_serialize_context_t493   objidx_t last_added_child_index() const {
494     if (unlikely (in_error ())) return (objidx_t) -1;
495 
496     assert (current);
497     if (!bool(current->real_links)) {
498       return (objidx_t) -1;
499     }
500 
501     return current->real_links[current->real_links.length - 1].objidx;
502   }
503 
504   // For the current object ensure that the sub-table bytes for child objidx are always placed
505   // after the subtable bytes for any other existing children. This only ensures that the
506   // repacker will not move the target subtable before the other children
507   // (by adding virtual links). It is up to the caller to ensure the initial serialization
508   // order is correct.
repack_lasthb_serialize_context_t509   void repack_last(objidx_t objidx) {
510     if (unlikely (in_error ())) return;
511 
512     if (!objidx)
513       return;
514 
515     assert (current);
516     for (auto& l : current->real_links) {
517       if (l.objidx == objidx) {
518         continue;
519       }
520 
521       packed[l.objidx]->add_virtual_link(objidx);
522     }
523   }
524 
525   template <typename T>
add_linkhb_serialize_context_t526   void add_link (T &ofs, objidx_t objidx,
527 		 whence_t whence = Head,
528 		 unsigned bias = 0)
529   {
530     if (unlikely (in_error ())) return;
531 
532     if (!objidx)
533       return;
534 
535     assert (current);
536     assert (current->head <= (const char *) &ofs);
537 
538     auto& link = *current->real_links.push ();
539     if (current->real_links.in_error ())
540       err (HB_SERIALIZE_ERROR_OTHER);
541 
542     link.width = sizeof (T);
543     link.objidx = objidx;
544     if (unlikely (!sizeof (T)))
545     {
546       // This link is not associated with an actual offset and exists merely to enforce
547       // an ordering constraint.
548       link.is_signed = 0;
549       link.whence = 0;
550       link.position = 0;
551       link.bias = 0;
552       return;
553     }
554 
555     link.is_signed = std::is_signed<hb_unwrap_type (T)>::value;
556     link.whence = (unsigned) whence;
557     link.position = (const char *) &ofs - current->head;
558     link.bias = bias;
559   }
560 
to_biashb_serialize_context_t561   unsigned to_bias (const void *base) const
562   {
563     if (unlikely (in_error ())) return 0;
564     if (!base) return 0;
565     assert (current);
566     assert (current->head <= (const char *) base);
567     return (const char *) base - current->head;
568   }
569 
resolve_linkshb_serialize_context_t570   void resolve_links ()
571   {
572     if (unlikely (in_error ())) return;
573 
574     assert (!current);
575     assert (packed.length > 1);
576 
577     for (const object_t* parent : ++hb_iter (packed))
578       for (const object_t::link_t &link : parent->real_links)
579       {
580 	const object_t* child = packed[link.objidx];
581 	if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
582 	unsigned offset = 0;
583 	switch ((whence_t) link.whence) {
584 	case Head:     offset = child->head - parent->head; break;
585 	case Tail:     offset = child->head - parent->tail; break;
586 	case Absolute: offset = (head - start) + (child->head - tail); break;
587 	}
588 
589 	assert (offset >= link.bias);
590 	offset -= link.bias;
591 	if (link.is_signed)
592 	{
593 	  assert (link.width == 2 || link.width == 4);
594 	  if (link.width == 4)
595 	    assign_offset<int32_t> (parent, link, offset);
596 	  else
597 	    assign_offset<int16_t> (parent, link, offset);
598 	}
599 	else
600 	{
601 	  assert (link.width == 2 || link.width == 3 || link.width == 4);
602 	  if (link.width == 4)
603 	    assign_offset<uint32_t> (parent, link, offset);
604 	  else if (link.width == 3)
605 	    assign_offset<uint32_t, 3> (parent, link, offset);
606 	  else
607 	    assign_offset<uint16_t> (parent, link, offset);
608 	}
609       }
610   }
611 
lengthhb_serialize_context_t612   unsigned int length () const
613   {
614     if (unlikely (!current)) return 0;
615     return this->head - current->head;
616   }
617 
alignhb_serialize_context_t618   void align (unsigned int alignment)
619   {
620     unsigned int l = length () % alignment;
621     if (l)
622       (void) allocate_size<void> (alignment - l);
623   }
624 
625   template <typename Type = void>
626   __attribute__((returns_nonnull))
start_embedhb_serialize_context_t627   Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
628   { return reinterpret_cast<Type *> (this->head); }
629   template <typename Type>
630   __attribute__((returns_nonnull))
start_embedhb_serialize_context_t631   Type *start_embed (const Type &obj) const
632   { return start_embed (std::addressof (obj)); }
633 
errhb_serialize_context_t634   bool err (hb_serialize_error_t err_type)
635   {
636     return !bool ((errors = (errors | err_type)));
637   }
638 
start_zerocopyhb_serialize_context_t639   bool start_zerocopy (size_t size)
640   {
641     if (unlikely (in_error ())) return false;
642 
643     if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
644     {
645       err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
646       return false;
647     }
648 
649     assert (!this->zerocopy);
650     this->zerocopy = this->head;
651 
652     assert (this->current->head == this->head);
653     this->current->head = this->current->tail = this->head = this->tail - size;
654     return true;
655   }
656 
657   template <typename Type>
658   HB_NODISCARD
allocate_sizehb_serialize_context_t659   Type *allocate_size (size_t size, bool clear = true)
660   {
661     if (unlikely (in_error ())) return nullptr;
662 
663     if (unlikely (size > INT_MAX || this->tail - this->head < ptrdiff_t (size)))
664     {
665       err (HB_SERIALIZE_ERROR_OUT_OF_ROOM);
666       return nullptr;
667     }
668     if (clear)
669       hb_memset (this->head, 0, size);
670     char *ret = this->head;
671     this->head += size;
672     return reinterpret_cast<Type *> (ret);
673   }
674 
675   template <typename Type>
allocate_minhb_serialize_context_t676   Type *allocate_min ()
677   { return this->allocate_size<Type> (Type::min_size); }
678 
679   template <typename Type>
680   HB_NODISCARD
embedhb_serialize_context_t681   Type *embed (const Type *obj)
682   {
683     unsigned int size = obj->get_size ();
684     Type *ret = this->allocate_size<Type> (size, false);
685     if (unlikely (!ret)) return nullptr;
686     hb_memcpy (ret, obj, size);
687     return ret;
688   }
689   template <typename Type>
690   HB_NODISCARD
embedhb_serialize_context_t691   Type *embed (const Type &obj)
692   { return embed (std::addressof (obj)); }
embedhb_serialize_context_t693   char *embed (const char *obj, unsigned size)
694   {
695     char *ret = this->allocate_size<char> (size, false);
696     if (unlikely (!ret)) return nullptr;
697     hb_memcpy (ret, obj, size);
698     return ret;
699   }
700 
701   template <typename Type, typename ...Ts> auto
_copyhb_serialize_context_t702   _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
703   (Type *, src.copy (this, std::forward<Ts> (ds)...))
704 
705   template <typename Type> auto
706   _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src))
707   {
708     Type *ret = this->allocate_size<Type> (sizeof (Type));
709     if (unlikely (!ret)) return nullptr;
710     *ret = src;
711     return ret;
712   }
713 
714   /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
715    * instead of hb_memcpy(). */
716   template <typename Type, typename ...Ts>
copyhb_serialize_context_t717   Type *copy (const Type &src, Ts&&... ds)
718   { return _copy (src, hb_prioritize, std::forward<Ts> (ds)...); }
719   template <typename Type, typename ...Ts>
copyhb_serialize_context_t720   Type *copy (const Type *src, Ts&&... ds)
721   { return copy (*src, std::forward<Ts> (ds)...); }
722 
723   template<typename Iterator,
724 	   hb_requires (hb_is_iterator (Iterator)),
725 	   typename ...Ts>
copy_allhb_serialize_context_t726   void copy_all (Iterator it, Ts&&... ds)
727   { for (decltype (*it) _ : it) copy (_, std::forward<Ts> (ds)...); }
728 
729   template <typename Type>
operator <<hb_serialize_context_t730   hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }
731 
732   template <typename Type>
extend_sizehb_serialize_context_t733   Type *extend_size (Type *obj, size_t size, bool clear = true)
734   {
735     if (unlikely (in_error ())) return nullptr;
736 
737     assert (this->start <= (char *) obj);
738     assert ((char *) obj <= this->head);
739     assert ((size_t) (this->head - (char *) obj) <= size);
740     if (unlikely (((char *) obj + size < (char *) obj) ||
741 		  !this->allocate_size<Type> (((char *) obj) + size - this->head, clear))) return nullptr;
742     return reinterpret_cast<Type *> (obj);
743   }
744   template <typename Type>
extend_sizehb_serialize_context_t745   Type *extend_size (Type &obj, size_t size, bool clear = true)
746   { return extend_size (std::addressof (obj), size, clear); }
747 
748   template <typename Type>
extend_minhb_serialize_context_t749   Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
750   template <typename Type>
extend_minhb_serialize_context_t751   Type *extend_min (Type &obj) { return extend_min (std::addressof (obj)); }
752 
753   template <typename Type, typename ...Ts>
extendhb_serialize_context_t754   Type *extend (Type *obj, Ts&&... ds)
755   { return extend_size (obj, obj->get_size (std::forward<Ts> (ds)...)); }
756   template <typename Type, typename ...Ts>
extendhb_serialize_context_t757   Type *extend (Type &obj, Ts&&... ds)
758   { return extend (std::addressof (obj), std::forward<Ts> (ds)...); }
759 
760   /* Output routines. */
copy_byteshb_serialize_context_t761   hb_bytes_t copy_bytes () const
762   {
763     assert (successful ());
764     /* Copy both items from head side and tail side... */
765     unsigned int len = (this->head - this->start)
766 		     + (this->end  - this->tail);
767 
768     // If len is zero don't hb_malloc as the memory won't get properly
769     // cleaned up later.
770     if (!len) return hb_bytes_t ();
771 
772     char *p = (char *) hb_malloc (len);
773     if (unlikely (!p)) return hb_bytes_t ();
774 
775     hb_memcpy (p, this->start, this->head - this->start);
776     hb_memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
777     return hb_bytes_t (p, len);
778   }
779   template <typename Type>
copyhb_serialize_context_t780   Type *copy () const
781   { return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); }
copy_blobhb_serialize_context_t782   hb_blob_t *copy_blob () const
783   {
784     hb_bytes_t b = copy_bytes ();
785     return hb_blob_create (b.arrayZ, b.length,
786 			   HB_MEMORY_MODE_WRITABLE,
787 			   (char *) b.arrayZ, hb_free);
788   }
789 
object_graphhb_serialize_context_t790   const hb_vector_t<object_t *>& object_graph() const
791   { return packed; }
792 
793   private:
794   template <typename T, unsigned Size = sizeof (T)>
assign_offsethb_serialize_context_t795   void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
796   {
797     auto &off = * ((BEInt<T, Size> *) (parent->head + link.position));
798     assert (0 == off);
799     check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW);
800   }
801 
802   public:
803   char *start, *head, *tail, *end, *zerocopy;
804   unsigned int debug_depth;
805   hb_serialize_error_t errors;
806 
807   private:
808 
merge_virtual_linkshb_serialize_context_t809   void merge_virtual_links (const object_t* from, objidx_t to_idx) {
810     object_t* to = packed[to_idx];
811     for (const auto& l : from->virtual_links) {
812       to->virtual_links.push (l);
813     }
814   }
815 
816   /* Object memory pool. */
817   hb_pool_t<object_t> object_pool;
818 
819   /* Stack of currently under construction objects. */
820   object_t *current;
821 
822   /* Stack of packed objects.  Object 0 is always nil object. */
823   hb_vector_t<object_t *> packed;
824 
825   /* Map view of packed objects. */
826   hb_hashmap_t<const object_t *, objidx_t> packed_map;
827 };
828 
829 #endif /* HB_SERIALIZE_HH */
830