Merge branch 'master' into var-subset
This commit is contained in:
commit
f7700fc479
|
@ -40,12 +40,12 @@ static const struct
|
||||||
//{ return hb_deref_pointer (v).hash (); }
|
//{ return hb_deref_pointer (v).hash (); }
|
||||||
/* Instead, the following ugly soution: */
|
/* Instead, the following ugly soution: */
|
||||||
template <typename T,
|
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 (); }
|
uint32_t operator () (T&& v) const { return v.hash (); }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
uint32_t operator () (const T *v) const
|
uint32_t operator () (const T *v) const
|
||||||
{ return hb_hash (v); }
|
{ return operator() (*v); }
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
hb_enable_if (hb_is_integer (T))>
|
hb_enable_if (hb_is_integer (T))>
|
||||||
|
|
|
@ -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); }
|
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
|
||||||
template <typename T> operator T * () const { return arrayZ; }
|
template <typename T> operator T * () const { return arrayZ; }
|
||||||
|
|
||||||
|
uint32_t hash () const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare, Sort, and Search.
|
* 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_])
|
hb_sorted_array (T (&array_)[length_])
|
||||||
{ return hb_sorted_array_t<T> (array_); }
|
{ 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 char> hb_bytes_t;
|
||||||
typedef hb_array_t<const unsigned char> hb_ubytes_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 */
|
#endif /* HB_ARRAY_HH */
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
* hb_hashmap_t
|
* 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,
|
template <typename K, typename V,
|
||||||
K kINVALID = hb_is_pointer (K) ? 0 : (K) -1,
|
K kINVALID = hb_is_pointer (K) ? 0 : (K) -1,
|
||||||
V vINVALID = hb_is_pointer (V) ? 0 : (V) -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 (K) || hb_is_pointer (K), "");
|
||||||
static_assert (hb_is_integer (V) || hb_is_pointer (V), "");
|
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
|
struct item_t
|
||||||
{
|
{
|
||||||
K key;
|
K key;
|
||||||
|
@ -82,14 +88,21 @@ struct hb_hashmap_t
|
||||||
{
|
{
|
||||||
free (items);
|
free (items);
|
||||||
items = nullptr;
|
items = nullptr;
|
||||||
|
population = occupancy = 0;
|
||||||
}
|
}
|
||||||
void fini ()
|
void fini ()
|
||||||
{
|
{
|
||||||
population = occupancy = 0;
|
|
||||||
hb_object_fini (this);
|
hb_object_fini (this);
|
||||||
fini_shallow ();
|
fini_shallow ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset ()
|
||||||
|
{
|
||||||
|
/* TODO Keep array? */
|
||||||
|
fini_shallow ();
|
||||||
|
init_shallow ();
|
||||||
|
}
|
||||||
|
|
||||||
bool in_error () const { return !successful; }
|
bool in_error () const { return !successful; }
|
||||||
|
|
||||||
bool resize ()
|
bool resize ()
|
||||||
|
@ -248,6 +261,10 @@ struct hb_hashmap_t
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hb_map_t
|
||||||
|
*/
|
||||||
|
|
||||||
struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
|
struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
|
||||||
hb_codepoint_t,
|
hb_codepoint_t,
|
||||||
HB_MAP_VALUE_INVALID,
|
HB_MAP_VALUE_INVALID,
|
||||||
|
|
|
@ -72,6 +72,17 @@ static const struct
|
||||||
} hb_deref_pointer HB_UNUSED;
|
} 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. */
|
/* Void! For when we need a expression-type of void. */
|
||||||
struct hb_void_t { typedef void value; };
|
struct hb_void_t { typedef void value; };
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "hb.hh"
|
#include "hb.hh"
|
||||||
#include "hb-blob.hh"
|
#include "hb-blob.hh"
|
||||||
|
#include "hb-map.hh"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -39,20 +40,70 @@
|
||||||
|
|
||||||
struct hb_serialize_context_t
|
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)
|
hb_serialize_context_t (void *start_, unsigned int size)
|
||||||
{
|
{
|
||||||
this->start = (char *) start_;
|
this->start = (char *) start_;
|
||||||
this->end = this->start + size;
|
this->end = this->start + size;
|
||||||
reset ();
|
reset ();
|
||||||
}
|
}
|
||||||
|
~hb_serialize_context_t ()
|
||||||
|
{
|
||||||
|
current.fini_deep ();
|
||||||
|
packed.fini_deep ();
|
||||||
|
packed_map.fini ();
|
||||||
|
}
|
||||||
|
|
||||||
bool in_error () const { return !this->successful; }
|
bool in_error () const { return !this->successful; }
|
||||||
|
|
||||||
void reset ()
|
void reset ()
|
||||||
{
|
{
|
||||||
this->successful = true;
|
this->successful = true;
|
||||||
|
this->ran_out_of_room = false;
|
||||||
this->head = this->start;
|
this->head = this->start;
|
||||||
|
this->tail = this->end;
|
||||||
this->debug_depth = 0;
|
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)
|
bool propagate_error (bool e)
|
||||||
|
@ -61,15 +112,10 @@ struct hb_serialize_context_t
|
||||||
{ return this->successful = this->successful && !obj.in_error (); }
|
{ return this->successful = this->successful && !obj.in_error (); }
|
||||||
template <typename T> bool propagate_error (const T *obj)
|
template <typename T> bool propagate_error (const T *obj)
|
||||||
{ return this->successful = this->successful && !obj->in_error (); }
|
{ return this->successful = this->successful && !obj->in_error (); }
|
||||||
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> bool propagate_error (T1 *o1, T2 *o2)
|
|
||||||
{ return propagate_error (o1) && propagate_error (o2); }
|
{ return propagate_error (o1) && propagate_error (o2); }
|
||||||
template <typename T1, typename T2, typename T3>
|
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); }
|
|
||||||
template <typename T1, typename T2, typename T3>
|
|
||||||
bool propagate_error (T1 *o1, T2 *o2, T3 *o3)
|
|
||||||
{ return propagate_error (o1) && propagate_error (o2, o3); }
|
{ return propagate_error (o1) && propagate_error (o2, o3); }
|
||||||
|
|
||||||
/* To be called around main operation. */
|
/* To be called around main operation. */
|
||||||
|
@ -81,18 +127,103 @@ struct hb_serialize_context_t
|
||||||
this->start, this->end,
|
this->start, this->end,
|
||||||
(unsigned long) (this->end - this->start));
|
(unsigned long) (this->end - this->start));
|
||||||
|
|
||||||
return start_embed<Type> ();
|
assert (!current.length);
|
||||||
|
return push<Type> ();
|
||||||
}
|
}
|
||||||
void end_serialize ()
|
void end_serialize ()
|
||||||
{
|
{
|
||||||
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
|
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,
|
this->start, this->end,
|
||||||
(int) (this->head - this->start),
|
(unsigned) (this->head - this->start),
|
||||||
this->successful ? "successful" : "UNSUCCESSFUL");
|
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)
|
void align (unsigned int alignment)
|
||||||
{
|
{
|
||||||
|
@ -111,7 +242,11 @@ struct hb_serialize_context_t
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
Type *allocate_size (unsigned int size)
|
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;
|
this->successful = false;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -156,40 +291,49 @@ struct hb_serialize_context_t
|
||||||
Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); }
|
Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); }
|
||||||
|
|
||||||
/* Output routines. */
|
/* 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
|
hb_bytes_t copy_bytes () const
|
||||||
{
|
{
|
||||||
assert (this->successful);
|
assert (this->successful);
|
||||||
unsigned int len = this->head - this->start;
|
/* Copy both items from head side and tail side... */
|
||||||
void *p = malloc (len);
|
unsigned int len = (this->head - this->start)
|
||||||
|
+ (this->end - this->tail);
|
||||||
|
char *p = (char *) malloc (len);
|
||||||
if (p)
|
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
|
else
|
||||||
return hb_bytes_t ();
|
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
|
hb_blob_t *copy_blob () const
|
||||||
{
|
{
|
||||||
assert (this->successful);
|
hb_bytes_t b = copy_bytes ();
|
||||||
return hb_blob_create (this->start,
|
return hb_blob_create (b.arrayZ, b.length,
|
||||||
this->head - this->start,
|
HB_MEMORY_MODE_WRITABLE,
|
||||||
HB_MEMORY_MODE_DUPLICATE,
|
(char *) b.arrayZ, free);
|
||||||
nullptr, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public: /* TODO Make private. */
|
||||||
|
char *start, *head, *tail, *end;
|
||||||
unsigned int debug_depth;
|
unsigned int debug_depth;
|
||||||
char *start, *end, *head;
|
|
||||||
bool successful;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ _subset2 (hb_subset_plan_t *plan)
|
||||||
hb_serialize_context_t serializer ((void *) buf, buf_size);
|
hb_serialize_context_t serializer ((void *) buf, buf_size);
|
||||||
hb_subset_context_t c (plan, &serializer);
|
hb_subset_context_t c (plan, &serializer);
|
||||||
result = table->subset (&c);
|
result = table->subset (&c);
|
||||||
if (serializer.in_error ())
|
if (serializer.ran_out_of_room)
|
||||||
{
|
{
|
||||||
buf_size += (buf_size >> 1) + 32;
|
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);
|
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;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
if (serializer.in_error ())
|
||||||
|
{
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
hb_blob_t *dest_blob = serializer.copy_blob ();
|
hb_blob_t *dest_blob = serializer.copy_blob ();
|
||||||
|
|
|
@ -38,8 +38,20 @@ struct hb_vector_t
|
||||||
typedef Type item_t;
|
typedef Type item_t;
|
||||||
static constexpr unsigned item_size = hb_static_size (Type);
|
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 () { 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 (); }
|
~hb_vector_t () { fini (); }
|
||||||
|
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
@ -69,6 +81,30 @@ struct hb_vector_t
|
||||||
fini ();
|
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_; }
|
const Type * arrayZ () const { return arrayZ_; }
|
||||||
Type * arrayZ () { return arrayZ_; }
|
Type * arrayZ () { return arrayZ_; }
|
||||||
|
|
||||||
|
@ -87,11 +123,15 @@ struct hb_vector_t
|
||||||
return arrayZ()[i];
|
return arrayZ()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type& tail () { return (*this)[length - 1]; }
|
||||||
|
const Type& tail () const { return (*this)[length - 1]; }
|
||||||
|
|
||||||
explicit operator bool () const { return length; }
|
explicit operator bool () const { return length; }
|
||||||
|
unsigned get_size () const { return length * item_size; }
|
||||||
|
|
||||||
/* Sink interface. */
|
/* Sink interface. */
|
||||||
template <typename T>
|
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< Type> as_array () { return hb_array (arrayZ(), length); }
|
||||||
hb_array_t<const Type> as_array () const { 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];
|
return &arrayZ()[length - 1];
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Type *push (const T& v)
|
Type *push (T&& v)
|
||||||
{
|
{
|
||||||
Type *p = push ();
|
Type *p = push ();
|
||||||
*p = v;
|
*p = hb_forward<T> (v);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,10 +228,10 @@ struct hb_vector_t
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop ()
|
Type pop ()
|
||||||
{
|
{
|
||||||
if (!length) return;
|
if (!length) return Null(Type);
|
||||||
length--;
|
return hb_move (arrayZ()[--length]); /* Does this move actually work? */
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove (unsigned int i)
|
void remove (unsigned int i)
|
||||||
|
|
Loading…
Reference in New Issue