Merge branch 'master' into var-subset

This commit is contained in:
Michiharu Ariza 2019-03-30 20:49:34 -07:00
commit f7700fc479
7 changed files with 274 additions and 44 deletions

View File

@ -40,12 +40,12 @@ static const struct
//{ return hb_deref_pointer (v).hash (); }
/* Instead, the following ugly soution: */
template <typename T,
hb_enable_if (!hb_is_integer (hb_remove_reference (T)) && !hb_is_pointer (T))>
hb_enable_if (!hb_is_integer (hb_remove_const (hb_remove_reference (T))) && !hb_is_pointer (T))>
uint32_t operator () (T&& v) const { return v.hash (); }
template <typename T>
uint32_t operator () (const T *v) const
{ return hb_hash (v); }
{ return operator() (*v); }
template <typename T,
hb_enable_if (hb_is_integer (T))>

View File

@ -79,6 +79,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
template <typename T> operator T * () const { return arrayZ; }
uint32_t hash () const;
/*
* Compare, Sort, and Search.
*/
@ -273,9 +275,20 @@ template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
hb_sorted_array (T (&array_)[length_])
{ return hb_sorted_array_t<T> (array_); }
template <typename T>
uint32_t hb_array_t<T>::hash () const
{
uint32_t h = 0;
for (unsigned i = 0; i < length; i++)
h ^= hb_hash (arrayZ[i]);
return h;
}
typedef hb_array_t<const char> hb_bytes_t;
typedef hb_array_t<const unsigned char> hb_ubytes_t;
/* TODO Specialize hashing for hb_bytes_t and hb_ubytes_t. */
//template <>
//uint32_t hb_array_t<const char>::hash () const { return 0; }
#endif /* HB_ARRAY_HH */

View File

@ -34,6 +34,8 @@
* hb_hashmap_t
*/
/* TODO if K/V is signed integer, -1 is not a good default.
* Don't know how to get to -MAX using bit work. */
template <typename K, typename V,
K kINVALID = hb_is_pointer (K) ? 0 : (K) -1,
V vINVALID = hb_is_pointer (V) ? 0 : (V) -1>
@ -46,6 +48,10 @@ struct hb_hashmap_t
static_assert (hb_is_integer (K) || hb_is_pointer (K), "");
static_assert (hb_is_integer (V) || hb_is_pointer (V), "");
/* TODO If key type is a pointer, keep hash in item_t and use to:
* 1. avoid rehashing when resizing table, and
* 2. compare hash before comparing keys, for speed.
*/
struct item_t
{
K key;
@ -82,14 +88,21 @@ struct hb_hashmap_t
{
free (items);
items = nullptr;
population = occupancy = 0;
}
void fini ()
{
population = occupancy = 0;
hb_object_fini (this);
fini_shallow ();
}
void reset ()
{
/* TODO Keep array? */
fini_shallow ();
init_shallow ();
}
bool in_error () const { return !successful; }
bool resize ()
@ -248,6 +261,10 @@ struct hb_hashmap_t
}
};
/*
* hb_map_t
*/
struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
hb_codepoint_t,
HB_MAP_VALUE_INVALID,

View File

@ -72,6 +72,17 @@ static const struct
} hb_deref_pointer HB_UNUSED;
/* std::move and std::forward */
template <typename T>
hb_remove_reference (T)&& hb_move (T&& t) { return (hb_remove_reference (T)&&) (t); }
template <typename T>
T&& hb_forward (hb_remove_reference (T)& t) { return (T&&) t; }
template <typename T>
T&& hb_forward (hb_remove_reference (T)&& t) { return (T&&) t; }
/* Void! For when we need a expression-type of void. */
struct hb_void_t { typedef void value; };

View File

@ -31,6 +31,7 @@
#include "hb.hh"
#include "hb-blob.hh"
#include "hb-map.hh"
/*
@ -39,20 +40,70 @@
struct hb_serialize_context_t
{
typedef unsigned objidx_t;
struct range_t
{
char *head, *tail;
};
struct object_t : range_t
{
void fini () { links.fini (); }
bool operator == (const object_t &o) const
{
return (tail - head == o.tail - o.head)
&& (links.length != o.links.length)
&& 0 == memcmp (head, o.head, tail - head)
&& 0 == memcmp (&links, &o.links, links.get_size ());
}
uint32_t hash () const
{
return hb_bytes_t (head, tail - head).hash () ^
links.as_bytes ().hash ();
}
struct link_t
{
bool wide: 1;
unsigned offset : 31;
objidx_t objidx;
};
hb_vector_t<link_t> links;
};
range_t snapshot () { range_t s = {head, tail} ; return s; }
hb_serialize_context_t (void *start_, unsigned int size)
{
this->start = (char *) start_;
this->end = this->start + size;
reset ();
}
~hb_serialize_context_t ()
{
current.fini_deep ();
packed.fini_deep ();
packed_map.fini ();
}
bool in_error () const { return !this->successful; }
void reset ()
{
this->successful = true;
this->ran_out_of_room = false;
this->head = this->start;
this->tail = this->end;
this->debug_depth = 0;
this->current.reset ();
this->packed.reset ();
this->packed.push ()->head = this->end;
this->packed_map.reset ();
}
bool propagate_error (bool e)
@ -61,15 +112,10 @@ struct hb_serialize_context_t
{ return this->successful = this->successful && !obj.in_error (); }
template <typename T> bool propagate_error (const T *obj)
{ return this->successful = this->successful && !obj->in_error (); }
template <typename T1, typename T2> bool propagate_error (T1 &o1, T2 &o2)
{ return propagate_error (o1) && propagate_error (o2); }
template <typename T1, typename T2> bool propagate_error (T1 *o1, T2 *o2)
template <typename T1, typename T2> bool propagate_error (T1 &&o1, T2 &&o2)
{ return propagate_error (o1) && propagate_error (o2); }
template <typename T1, typename T2, typename T3>
bool propagate_error (T1 &o1, T2 &o2, T3 &o3)
{ return propagate_error (o1) && propagate_error (o2, o3); }
template <typename T1, typename T2, typename T3>
bool propagate_error (T1 *o1, T2 *o2, T3 *o3)
bool propagate_error (T1 &&o1, T2 &&o2, T3 &&o3)
{ return propagate_error (o1) && propagate_error (o2, o3); }
/* To be called around main operation. */
@ -81,18 +127,103 @@ struct hb_serialize_context_t
this->start, this->end,
(unsigned long) (this->end - this->start));
return start_embed<Type> ();
assert (!current.length);
return push<Type> ();
}
void end_serialize ()
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
"end [%p..%p] serialized %d bytes; %s",
"end [%p..%p] serialized %u bytes; %s",
this->start, this->end,
(int) (this->head - this->start),
(unsigned) (this->head - this->start),
this->successful ? "successful" : "UNSUCCESSFUL");
/* TODO Propagate errors. */
assert (current.length == 1);
/* Only "pack" if there exist other objects... Otherwise, don't bother.
* Saves a move. */
if (packed.length == 1)
return;
pop_pack ();
link ();
}
unsigned int length () const { return this->head - this->start; }
template <typename Type>
Type *push ()
{
object_t obj;
obj.head = head;
obj.tail = tail;
current.push (obj);
return start_embed<Type> ();
}
void pop_discard ()
{
revert (current.pop ());
}
objidx_t pop_pack ()
{
object_t obj = current.pop ();
obj.tail = head;
unsigned len = obj.tail - obj.head;
objidx_t objidx = packed_map.get (&obj);
if (objidx)
{
obj.fini ();
return objidx;
}
tail -= len;
memmove (tail, obj.head, len);
head = obj.head;
if (!len)
return 0;
obj.head = tail;
obj.tail = tail + len;
object_t *key = packed.push (hb_move (obj));
/* TODO Handle error. */
if (unlikely (packed.in_error ()))
return 0;
objidx = packed.length - 1;
packed_map.set (key, objidx);
return objidx;
}
void revert (range_t snap)
{
assert (snap.head <= head);
assert (tail <= snap.tail);
head = snap.head;
tail = snap.tail;
discard_stale_objects ();
}
void discard_stale_objects ()
{
while (packed.length > 1 &&
packed.tail ().head < tail)
packed.pop ();
assert (packed.tail ().head == tail);
}
void link ()
{
// XXX
}
unsigned int length () const { return this->head - current.tail ().head; }
void align (unsigned int alignment)
{
@ -111,7 +242,11 @@ struct hb_serialize_context_t
template <typename Type>
Type *allocate_size (unsigned int size)
{
if (unlikely (!this->successful || this->end - this->head < ptrdiff_t (size))) {
if (unlikely (!this->successful)) return nullptr;
if (this->tail - this->head < ptrdiff_t (size))
{
this->ran_out_of_room = true;
this->successful = false;
return nullptr;
}
@ -156,40 +291,49 @@ struct hb_serialize_context_t
Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); }
/* Output routines. */
template <typename Type>
Type *copy () const
{
assert (this->successful);
unsigned int len = this->head - this->start;
void *p = malloc (len);
if (p)
memcpy (p, this->start, len);
return reinterpret_cast<Type *> (p);
}
hb_bytes_t copy_bytes () const
{
assert (this->successful);
unsigned int len = this->head - this->start;
void *p = malloc (len);
/* Copy both items from head side and tail side... */
unsigned int len = (this->head - this->start)
+ (this->end - this->tail);
char *p = (char *) malloc (len);
if (p)
memcpy (p, this->start, len);
{
memcpy (p, this->start, this->head - this->start);
memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
}
else
return hb_bytes_t ();
return hb_bytes_t ((char *) p, len);
return hb_bytes_t (p, len);
}
template <typename Type>
Type *copy () const
{ return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); }
hb_blob_t *copy_blob () const
{
assert (this->successful);
return hb_blob_create (this->start,
this->head - this->start,
HB_MEMORY_MODE_DUPLICATE,
nullptr, nullptr);
hb_bytes_t b = copy_bytes ();
return hb_blob_create (b.arrayZ, b.length,
HB_MEMORY_MODE_WRITABLE,
(char *) b.arrayZ, free);
}
public:
public: /* TODO Make private. */
char *start, *head, *tail, *end;
unsigned int debug_depth;
char *start, *end, *head;
bool successful;
bool ran_out_of_room;
private:
/* Stack of currently under construction objects. */
hb_vector_t<object_t> current;
/* Stack of packed objects. Object 0 is always nil object. */
hb_vector_t<object_t> packed;
/* Map view of packed objects. */
hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
};

View File

@ -85,7 +85,7 @@ _subset2 (hb_subset_plan_t *plan)
hb_serialize_context_t serializer ((void *) buf, buf_size);
hb_subset_context_t c (plan, &serializer);
result = table->subset (&c);
if (serializer.in_error ())
if (serializer.ran_out_of_room)
{
buf_size += (buf_size >> 1) + 32;
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
@ -96,6 +96,11 @@ _subset2 (hb_subset_plan_t *plan)
}
goto retry;
}
if (serializer.in_error ())
{
abort ();
}
if (result)
{
hb_blob_t *dest_blob = serializer.copy_blob ();

View File

@ -38,8 +38,20 @@ struct hb_vector_t
typedef Type item_t;
static constexpr unsigned item_size = hb_static_size (Type);
HB_NO_COPY_ASSIGN_TEMPLATE (hb_vector_t, Type);
hb_vector_t () { init (); }
hb_vector_t (const hb_vector_t &o)
{
init ();
alloc (o.length);
hb_iter (o) | hb_sink (this);
}
hb_vector_t (hb_vector_t &&o)
{
allocated = o.allocated;
length = o.length;
arrayZ_ = o.arrayZ_;
o.init ();
}
~hb_vector_t () { fini (); }
unsigned int length;
@ -69,6 +81,30 @@ struct hb_vector_t
fini ();
}
void reset () { resize (0); }
hb_vector_t& operator = (const hb_vector_t &o)
{
reset ();
alloc (o.length);
hb_iter (o) | hb_sink (this);
return *this;
}
hb_vector_t& operator = (hb_vector_t &&o)
{
fini ();
allocated = o.allocated;
length = o.length;
arrayZ_ = o.arrayZ_;
o.init ();
return *this;
}
hb_bytes_t as_bytes () const { return hb_bytes_t ((const char *) arrayZ_,
length * item_size); }
uint32_t hash () const { return as_bytes ().hash (); }
const Type * arrayZ () const { return arrayZ_; }
Type * arrayZ () { return arrayZ_; }
@ -87,11 +123,15 @@ struct hb_vector_t
return arrayZ()[i];
}
Type& tail () { return (*this)[length - 1]; }
const Type& tail () const { return (*this)[length - 1]; }
explicit operator bool () const { return length; }
unsigned get_size () const { return length * item_size; }
/* Sink interface. */
template <typename T>
hb_vector_t& operator << (const T& v) { push (v); return *this; }
hb_vector_t& operator << (T&& v) { push (hb_forward<T> (v)); return *this; }
hb_array_t< Type> as_array () { return hb_array (arrayZ(), length); }
hb_array_t<const Type> as_array () const { return hb_array (arrayZ(), length); }
@ -131,10 +171,10 @@ struct hb_vector_t
return &arrayZ()[length - 1];
}
template <typename T>
Type *push (const T& v)
Type *push (T&& v)
{
Type *p = push ();
*p = v;
*p = hb_forward<T> (v);
return p;
}
@ -188,10 +228,10 @@ struct hb_vector_t
return true;
}
void pop ()
Type pop ()
{
if (!length) return;
length--;
if (!length) return Null(Type);
return hb_move (arrayZ()[--length]); /* Does this move actually work? */
}
void remove (unsigned int i)