Merge branch 'master' into iter
diff --git a/configure.ac b/configure.ac
index 989de12..69c944d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@
AC_PROG_CC_C99
AM_PROG_CC_C_O
AC_PROG_CXX
-dnl AX_CXX_COMPILE_STDCXX(11, noext, optional)
+AX_CXX_COMPILE_STDCXX(11,, optional)
AC_SYS_LARGEFILE
PKG_PROG_PKG_CONFIG([0.20])
AM_MISSING_PROG([RAGEL], [ragel])
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 0da4abe..8eb235b 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -16,6 +16,7 @@
hb-aat-ltag-table.hh \
hb-aat-map.cc \
hb-aat-map.hh \
+ hb-algs.hh \
hb-array.hh \
hb-atomic.hh \
hb-blob.cc \
@@ -31,7 +32,6 @@
hb-cff2-interp-cs.hh \
hb-common.cc \
hb-debug.hh \
- hb-dsalgs.hh \
hb-face.cc \
hb-face.hh \
hb-font.cc \
@@ -41,6 +41,7 @@
hb-machinery.hh \
hb-map.cc \
hb-map.hh \
+ hb-meta.hh \
hb-mutex.hh \
hb-null.hh \
hb-object.hh \
diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh
index 3d5ad0e..f103d27 100644
--- a/src/hb-aat-map.hh
+++ b/src/hb-aat-map.hh
@@ -84,7 +84,7 @@
hb_face_t *face;
public:
- hb_vector_t<feature_info_t> features;
+ hb_sorted_vector_t<feature_info_t> features;
};
diff --git a/src/hb-dsalgs.hh b/src/hb-algs.hh
similarity index 90%
rename from src/hb-dsalgs.hh
rename to src/hb-algs.hh
index cb3057c..b4e79e8 100644
--- a/src/hb-dsalgs.hh
+++ b/src/hb-algs.hh
@@ -24,16 +24,52 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_DSALGS_HH
-#define HB_DSALGS_HH
+#ifndef HB_ALGS_HH
+#define HB_ALGS_HH
#include "hb.hh"
#include "hb-null.hh"
-/* Void! For when we need a expression-type of void. */
-typedef const struct _hb_void_t *hb_void_t;
-#define HB_VOID ((const _hb_void_t *) nullptr)
+template <typename T>
+inline typename T::iter_t
+hb_iter (const T& c) { return c.iter (); }
+
+static HB_UNUSED struct hb_identity_t
+{
+ template <typename T> T
+ operator () (const T& v) const { return v; }
+} hb_identity;
+
+template <typename T1, typename T2>
+struct hb_pair_t
+{
+ typedef T1 first_t;
+ typedef T2 second_t;
+ typedef hb_pair_t<T1, T2> pair_t;
+
+ hb_pair_t (const T1& a, const T2& b) : first (a), second (b) {}
+ hb_pair_t (const pair_t& o) : first (o.first), second (o.second) {}
+
+ bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
+
+ T1 first;
+ T2 second;
+};
+template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
+hb_pair (T1 a, T2 b) { return hb_pair_t<T1, T2> (a, b); }
+
+static HB_UNUSED struct hb_first_t
+{
+ template <typename Pair> typename Pair::first_t
+ operator () (const Pair& pair) const { return pair.first; }
+} hb_first;
+
+static HB_UNUSED struct hb_second_t
+{
+ template <typename Pair> typename Pair::second_t
+ operator () (const Pair& pair) const { return pair.second; }
+} hb_second;
/*
@@ -233,8 +269,8 @@
* Tiny stuff.
*/
-template <typename T>
-static inline T* hb_addressof (T& arg)
+template <typename T> static inline T*
+hb_addressof (const T& arg)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
@@ -298,26 +334,6 @@
return ((v - 1) | 3) + 1;
}
-template <typename T> struct hb_is_signed;
-template <> struct hb_is_signed<signed char> { enum { value = true }; };
-template <> struct hb_is_signed<signed short> { enum { value = true }; };
-template <> struct hb_is_signed<signed int> { enum { value = true }; };
-template <> struct hb_is_signed<signed long> { enum { value = true }; };
-template <> struct hb_is_signed<unsigned char> { enum { value = false }; };
-template <> struct hb_is_signed<unsigned short> { enum { value = false }; };
-template <> struct hb_is_signed<unsigned int> { enum { value = false }; };
-template <> struct hb_is_signed<unsigned long> { enum { value = false }; };
-/* We need to define hb_is_signed for the typedefs we use on pre-Visual
- * Studio 2010 for the int8_t type, since __int8/__int64 is not considered
- * the same as char/long. The previous lines will suffice for the other
- * types, though. Note that somehow, unsigned __int8 is considered same
- * as unsigned char.
- * https://github.com/harfbuzz/harfbuzz/pull/1499
- */
-#if defined(_MSC_VER) && (_MSC_VER < 1600)
-template <> struct hb_is_signed<__int8> { enum { value = true }; };
-#endif
-
template <typename T> static inline bool
hb_in_range (T u, T lo, T hi)
{
@@ -496,16 +512,17 @@
}
}
-static inline void hb_sort_r(void *base, size_t nel, size_t width,
- int (*compar)(const void *_a, const void *_b, void *_arg),
- void *arg)
+static inline void
+hb_sort_r (void *base, size_t nel, size_t width,
+ int (*compar)(const void *_a, const void *_b, void *_arg),
+ void *arg)
{
sort_r_simple(base, nel, width, compar, arg);
}
-template <typename T, typename T2> static inline void
-hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
+template <typename T, typename T2, typename T3> static inline void
+hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
{
for (unsigned int i = 1; i < len; i++)
{
@@ -522,8 +539,8 @@
}
if (array2)
{
- T2 t = array2[i];
- memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
+ T3 t = array2[i];
+ memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
array2[j] = t;
}
}
@@ -638,4 +655,4 @@
};
-#endif /* HB_DSALGS_HH */
+#endif /* HB_ALGS_HH */
diff --git a/src/hb-array.hh b/src/hb-array.hh
index 52b775e..62075c4 100644
--- a/src/hb-array.hh
+++ b/src/hb-array.hh
@@ -28,7 +28,7 @@
#define HB_ARRAY_HH
#include "hb.hh"
-#include "hb-dsalgs.hh"
+#include "hb-algs.hh"
#include "hb-iter.hh"
#include "hb-null.hh"
@@ -38,21 +38,24 @@
template <typename Type>
struct hb_array_t :
- hb_iter_t<hb_array_t<Type>, Type>,
- hb_iter_mixin_t<hb_array_t<Type>, Type>
+ hb_iter_t<hb_array_t<Type>, Type&>,
+ hb_iter_mixin_t<hb_array_t<Type>, Type&>
{
/*
* Constructors.
*/
hb_array_t () : arrayZ (nullptr), length (0) {}
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
+ template <typename U = Type, hb_enable_if (hb_is_const (U))>
+ hb_array_t (const hb_array_t<hb_remove_const (Type)> &o) : arrayZ (o.arrayZ), length (o.length) {}
template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
/*
* Iterator implementation.
*/
- typedef Type __item_type__;
+ typedef Type& __item_t__;
+ static constexpr bool is_random_access_iterator = true;
Type& __item_at__ (unsigned i) const
{
if (unlikely (i >= length)) return CrapOrNull (Type);
@@ -72,7 +75,6 @@
length -= n;
}
unsigned __len__ () const { return length; }
- bool __random_access__ () const { return true; }
/* Extra operators.
*/
@@ -193,12 +195,18 @@
template <typename Type>
struct hb_sorted_array_t :
- hb_sorted_iter_t<hb_sorted_array_t<Type>, Type>,
- hb_array_t<Type>,
- hb_iter_mixin_t<hb_sorted_array_t<Type>, Type>
+ hb_iter_t<hb_sorted_array_t<Type>, Type&>,
+ hb_array_t<Type>
{
+ typedef hb_iter_t<hb_sorted_array_t<Type>, Type&> iter_base_t;
+ HB_ITER_USING (iter_base_t);
+ static constexpr bool is_random_access_iterator = true;
+ static constexpr bool is_sorted_iterator = true;
+
hb_sorted_array_t () : hb_array_t<Type> () {}
hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
+ template <typename U = Type, hb_enable_if (hb_is_const (U))>
+ hb_sorted_array_t (const hb_sorted_array_t<hb_remove_const (Type)> &o) : hb_array_t<Type> (o) {}
hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh
index 9321932..d17c50b 100644
--- a/src/hb-atomic.hh
+++ b/src/hb-atomic.hh
@@ -33,6 +33,7 @@
#define HB_ATOMIC_HH
#include "hb.hh"
+#include "hb-meta.hh"
/*
@@ -282,7 +283,7 @@
template <typename P>
struct hb_atomic_ptr_t
{
- typedef typename hb_remove_pointer (P) T;
+ typedef hb_remove_pointer (P) T;
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
diff --git a/src/hb-blob.hh b/src/hb-blob.hh
index 4ea13f8..3a30efe 100644
--- a/src/hb-blob.hh
+++ b/src/hb-blob.hh
@@ -81,7 +81,7 @@
template <typename P>
struct hb_blob_ptr_t
{
- typedef typename hb_remove_pointer (P) T;
+ typedef hb_remove_pointer (P) T;
hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {}
hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; }
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index d7d0165..cf938b2 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -29,7 +29,7 @@
#include "hb.hh"
#include "hb-atomic.hh"
-#include "hb-dsalgs.hh"
+#include "hb-algs.hh"
#ifndef HB_DEBUG
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
index c4ab26d..b538ddf 100644
--- a/src/hb-iter.hh
+++ b/src/hb-iter.hh
@@ -28,6 +28,8 @@
#define HB_ITER_HH
#include "hb.hh"
+#include "hb-algs.hh" // for hb_addressof
+#include "hb-meta.hh"
#include "hb-null.hh"
@@ -41,14 +43,21 @@
* returns rvalues.
*/
+
+/*
+ * Base classes for iterators.
+ */
+
/* Base class for all iterators. */
-template <typename Iter, typename Item = typename Iter::__item_type__>
+template <typename Iter, typename Item = typename Iter::__item_t__>
struct hb_iter_t
{
typedef Iter iter_t;
- typedef iter_t const_iter_t;
typedef Item item_t;
static constexpr unsigned item_size = hb_static_size (Item);
+ static constexpr bool is_iterator = true;
+ static constexpr bool is_random_access_iterator = false;
+ static constexpr bool is_sorted_iterator = false;
private:
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -56,32 +65,26 @@
iter_t* thiz () { return static_cast< iter_t *> (this); }
public:
- /* Operators. */
- operator iter_t () { return iter(); }
- explicit_operator bool () const { return more (); }
- item_t& operator * () const { return item (); }
- item_t& operator [] (signed i) const { return item_at ((unsigned) i); }
- iter_t& operator += (unsigned count) { forward (count); return *thiz(); }
- iter_t& operator ++ () { next (); return *thiz(); }
- iter_t& operator -= (unsigned count) { rewind (count); return *thiz(); }
- iter_t& operator -- () { prev (); return *thiz(); }
- iter_t operator + (unsigned count) { iter_t c (*thiz()); c += count; return c; }
- iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
- iter_t operator - (unsigned count) { iter_t c (*thiz()); c -= count; return c; }
- iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
+ /* TODO:
+ * Port operators below to use hb_enable_if to sniff which method implements
+ * an operator and use it, and remove hb_iter_mixin_t completely. */
- /* Methods. */
+ /* Operators. */
iter_t iter () const { return *thiz(); }
- const_iter_t const_iter () const { return iter (); }
- item_t& item () const { return thiz()->__item__ (); }
- item_t& item_at (unsigned i) const { return thiz()->__item_at__ (i); }
- bool more () const { return thiz()->__more__ (); }
+ explicit_operator bool () const { return thiz()->__more__ (); }
unsigned len () const { return thiz()->__len__ (); }
- void next () { thiz()->__next__ (); }
- void forward (unsigned n) { thiz()->__forward__ (n); }
- void prev () { thiz()->__prev__ (); }
- void rewind (unsigned n) { thiz()->__rewind__ (n); }
- bool random_access () const { return thiz()->__random_access__ (); }
+ hb_remove_reference (item_t)* operator -> () const { return hb_addressof (**thiz()); }
+ item_t operator * () const { return thiz()->__item__ (); }
+ item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
+ iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
+ iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
+ iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
+ iter_t& operator -- () { thiz()->__prev__ (); return *thiz(); }
+ iter_t operator + (unsigned count) const { iter_t c (*thiz()); c += count; return c; }
+ friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
+ iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
+ iter_t operator - (unsigned count) const { iter_t c (*thiz()); c -= count; return c; }
+ iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
protected:
hb_iter_t () {}
@@ -89,19 +92,27 @@
void operator = (const hb_iter_t &o HB_UNUSED) {}
};
-/* Base class for sorted iterators. Does not enforce anything.
- * Just for class taxonomy and requirements. */
-template <typename Iter, typename Item = typename Iter::__item_type__>
-struct hb_sorted_iter_t : hb_iter_t<Iter, Item>
-{
- protected:
- hb_sorted_iter_t () {}
- hb_sorted_iter_t (const hb_sorted_iter_t &o) : hb_iter_t<Iter, Item> (o) {}
- void operator = (const hb_sorted_iter_t &o HB_UNUSED) {}
-};
+#define HB_ITER_USING(Name) \
+ using iter_t = typename Name::iter_t; \
+ using item_t = typename Name::item_t; \
+ using Name::item_size; \
+ using Name::is_iterator; \
+ using Name::iter; \
+ using Name::operator bool; \
+ using Name::len; \
+ using Name::operator ->; \
+ using Name::operator *; \
+ using Name::operator []; \
+ using Name::operator +=; \
+ using Name::operator ++; \
+ using Name::operator -=; \
+ using Name::operator --; \
+ using Name::operator +; \
+ using Name::operator -; \
+ static_assert (true, "")
/* Mixin to fill in what the subclass doesn't provide. */
-template <typename iter_t, typename item_t = typename iter_t::__item_type__>
+template <typename iter_t, typename item_t = typename iter_t::__item_t__>
struct hb_iter_mixin_t
{
private:
@@ -111,38 +122,222 @@
public:
/* Access: Implement __item__(), or __item_at__() if random-access. */
- item_t& __item__ () const { return thiz()->item_at (0); }
- item_t& __item_at__ (unsigned i) const { return *(thiz() + i); }
+ item_t __item__ () const { return (*thiz())[0]; }
+ item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
/* Termination: Implement __more__(), or __len__() if random-access. */
- bool __more__ () const { return thiz()->__len__ (); }
+ bool __more__ () const { return thiz()->len (); }
unsigned __len__ () const
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; }
/* Advancing: Implement __next__(), or __forward__() if random-access. */
- void __next__ () { thiz()->forward (1); }
- void __forward__ (unsigned n) { while (n--) thiz()->next (); }
+ void __next__ () { *thiz() += 1; }
+ void __forward__ (unsigned n) { while (n--) ++*thiz(); }
/* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
- void __prev__ () { thiz()->rewind (1); }
- void __rewind__ (unsigned n) { while (n--) thiz()->prev (); }
+ void __prev__ () { *thiz() -= 1; }
+ void __rewind__ (unsigned n) { while (n--) --*thiz(); }
- /* Random access: Return true if item_at(), len(), forward() are fast. */
- bool __random_access__ () const { return false; }
+ protected:
+ hb_iter_mixin_t () {}
+ hb_iter_mixin_t (const hb_iter_mixin_t &o HB_UNUSED) {}
+ void operator = (const hb_iter_mixin_t &o HB_UNUSED) {}
};
+/*
+ * Meta-programming predicates.
+ */
-/* Functions operating on iterators or iteratables. */
+/* hb_is_iterable() */
-template <typename C, typename V> inline void
-hb_fill (const C& c, const V &v)
+template<typename T, typename B>
+struct _hb_is_iterable
+{ enum { value = false }; };
+template<typename T>
+struct _hb_is_iterable<T, hb_bool_tt<true || sizeof (Null(T).iter ())> >
+{ enum { value = true }; };
+
+template<typename T>
+struct hb_is_iterable { enum { value = _hb_is_iterable<T, hb_true_t>::value }; };
+#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
+
+/* TODO Add hb_is_iterable_of().
+ * TODO Add random_access / sorted variants. */
+
+
+/* hb_is_iterator() / hb_is_random_access_iterator() / hb_is_sorted_iterator() */
+
+template <typename Iter>
+struct _hb_is_iterator_of
+{
+ char operator () (...) { return 0; }
+ template<typename Item> int operator () (hb_iter_t<Iter, Item> *) { return 0; }
+ template<typename Item> int operator () (hb_iter_t<Iter, const Item> *) { return 0; }
+ template<typename Item> int operator () (hb_iter_t<Iter, Item&> *) { return 0; }
+ template<typename Item> int operator () (hb_iter_t<Iter, const Item&> *) { return 0; }
+ static_assert (sizeof (char) != sizeof (int), "");
+};
+template<typename Iter, typename Item>
+struct hb_is_iterator_of { enum {
+ value = sizeof (int) == sizeof (hb_declval (_hb_is_iterator_of<Iter>) (hb_declval (Iter*))) }; };
+#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
+#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
+
+#define hb_is_random_access_iterator_of(Iter, Item) \
+ hb_is_iterator_of (Iter, Item) && Iter::is_random_access_iterator
+#define hb_is_random_access_iterator(Iter) \
+ hb_is_random_access_iterator_of (Iter, typename Iter::item_t)
+
+#define hb_is_sorted_iterator_of(Iter, Item) \
+ hb_is_iterator_of (Iter, Item) && Iter::is_sorted_iterator
+#define hb_is_sorted_iterator(Iter) \
+ hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
+
+
+/*
+ * Adaptors, combiners, etc.
+ */
+
+template <typename Lhs, typename Rhs,
+ hb_enable_if (hb_is_iterator (Lhs))>
+static inline decltype (hb_declval (Rhs) (hb_declval (Lhs)))
+operator | (Lhs lhs, const Rhs &rhs) { return rhs (lhs); }
+
+/* hb_map(), hb_filter(), hb_reduce() */
+
+template <typename Iter, typename Proj,
+ hb_enable_if (hb_is_iterator (Iter))>
+struct hb_map_iter_t :
+ hb_iter_t<hb_map_iter_t<Iter, Proj>, decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t)))>
+{
+ hb_map_iter_t (const Iter& it, Proj&& f) : it (it), f (f) {}
+
+ typedef decltype (hb_declval (Proj) (hb_declval (typename Iter::item_t))) __item_t__;
+ static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
+ __item_t__ __item__ () const { return f (*it); }
+ __item_t__ __item_at__ (unsigned i) const { return f (it[i]); }
+ bool __more__ () const { return bool (it); }
+ unsigned __len__ () const { return it.len (); }
+ void __next__ () { ++it; }
+ void __forward__ (unsigned n) { it += n; }
+ void __prev__ () { --it; }
+ void __rewind__ (unsigned n) { it -= n; }
+
+ private:
+ Iter it;
+ Proj f;
+};
+template <typename Proj>
+struct hb_map_iter_factory_t
+{
+ hb_map_iter_factory_t (Proj&& f) : f (f) {}
+
+ template <typename Iterable,
+ hb_enable_if (hb_is_iterable (Iterable))>
+ hb_map_iter_t<typename Iterable::iter_t, Proj> operator () (const Iterable &c) const
+ { return hb_map_iter_t<typename Iterable::iter_t, Proj> (c.iter (), f); }
+
+ private:
+ Proj f;
+};
+template <typename Proj>
+inline hb_map_iter_factory_t<Proj>
+hb_map (Proj&& f)
+{ return hb_map_iter_factory_t<Proj> (f); }
+
+template <typename Iter, typename Pred, typename Proj,
+ hb_enable_if (hb_is_iterator (Iter))>
+struct hb_filter_iter_t :
+ hb_iter_t<hb_filter_iter_t<Iter, Pred, Proj>, typename Iter::item_t>,
+ hb_iter_mixin_t<hb_filter_iter_t<Iter, Pred, Proj>, typename Iter::item_t>
+{
+ hb_filter_iter_t (const Iter& it_, Pred&& p, Proj&& f) : it (it_), p (p), f (f)
+ { while (it && !p (f (*it))) ++it; }
+
+ typedef typename Iter::item_t __item_t__;
+ static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
+ __item_t__ __item__ () const { return *it; }
+ bool __more__ () const { return bool (it); }
+ void __next__ () { do ++it; while (it && !p (f (*it))); }
+ void __prev__ () { --it; }
+
+ private:
+ Iter it;
+ Pred p;
+ Proj f;
+};
+template <typename Pred, typename Proj>
+struct hb_filter_iter_factory_t
+{
+ hb_filter_iter_factory_t (Pred&& p, Proj&& f) : p (p), f (f) {}
+
+ template <typename Iterable,
+ hb_enable_if (hb_is_iterable (Iterable))>
+ hb_filter_iter_t<typename Iterable::iter_t, Pred, Proj> operator () (const Iterable &c) const
+ { return hb_filter_iter_t<typename Iterable::iter_t, Pred, Proj> (c.iter (), p, f); }
+
+ private:
+ Pred p;
+ Proj f;
+};
+template <typename Pred, typename Proj = hb_identity_t&>
+inline hb_filter_iter_factory_t<Pred, Proj>
+hb_filter (Pred&& p, Proj&& f = hb_identity)
+{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
+
+/* hb_zip() */
+
+template <typename A, typename B>
+struct hb_zip_iter_t :
+ hb_iter_t<hb_zip_iter_t<A, B>, hb_pair_t<typename A::item_t, typename B::item_t> >
+{
+ hb_zip_iter_t () {}
+ hb_zip_iter_t (A a, B b) : a (a), b (b) {}
+
+ typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
+ static constexpr bool is_random_access_iterator =
+ A::is_random_access_iterator &&
+ B::is_random_access_iterator;
+ static constexpr bool is_sorted_iterator =
+ A::is_sorted_iterator &&
+ B::is_sorted_iterator;
+ __item_t__ __item__ () const { return __item_t__ (*a, *b); }
+ __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
+ bool __more__ () const { return a && b; }
+ unsigned __len__ () const { return MIN (a.len (), b.len ()); }
+ void __next__ () { ++a; ++b; }
+ void __forward__ (unsigned n) { a += n; b += n; }
+ void __prev__ () { --a; --b; }
+ void __rewind__ (unsigned n) { a -= n; b -= n; }
+
+ private:
+ A a;
+ B b;
+};
+template <typename A, typename B,
+ hb_enable_if (hb_is_iterable (A) && hb_is_iterable (B))>
+inline hb_zip_iter_t<typename A::iter_t, typename B::iter_t>
+hb_zip (const A& a, const B &b)
+{ return hb_zip_iter_t<typename A::iter_t, typename B::iter_t> (a.iter (), b.iter ()); }
+
+
+/*
+ * Algorithms operating on iterators.
+ */
+
+template <typename C, typename V,
+ hb_enable_if (hb_is_iterable (C))>
+inline void
+hb_fill (C& c, const V &v)
{
for (typename C::iter_t i (c); i; i++)
hb_assign (*i, v);
}
-template <typename S, typename D> inline bool
-hb_copy (hb_iter_t<D> &id, hb_iter_t<S> &is)
+template <typename S, typename D,
+ hb_enable_if (hb_is_iterator (S) && hb_is_iterator (D))>
+inline bool
+hb_copy (D id, S is)
{
for (; id && is; ++id, ++is)
*id = *is;
diff --git a/src/hb-map.hh b/src/hb-map.hh
index 02d5406..8905421 100644
--- a/src/hb-map.hh
+++ b/src/hb-map.hh
@@ -160,14 +160,15 @@
void del (hb_codepoint_t key) { set (key, INVALID); }
- bool has (hb_codepoint_t key) const
- { return get (key) != INVALID; }
-
- hb_codepoint_t operator [] (unsigned int key) const
- { return get (key); }
-
static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
+ /* Map interface. */
+ static constexpr hb_codepoint_t SENTINEL = INVALID;
+ typedef hb_codepoint_t value_t;
+ value_t operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator () (hb_codepoint_t k) const { return has (k); }
+
void clear ()
{
memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
diff --git a/src/hb-meta.hh b/src/hb-meta.hh
new file mode 100644
index 0000000..a9f9df9
--- /dev/null
+++ b/src/hb-meta.hh
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2018 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_META_HH
+#define HB_META_HH
+
+#include "hb.hh"
+
+
+/*
+ * C++ Template Meta-programming.
+ */
+
+
+template <typename T> static inline T hb_declval ();
+#define hb_declval(T) (hb_declval<T> ())
+
+template <typename T> struct hb_match_const { typedef T type; enum { value = false }; };
+template <typename T> struct hb_match_const<const T> { typedef T type; enum { value = true }; };
+#define hb_remove_const(T) typename hb_match_const<T>::type
+#define hb_is_const(T) hb_match_const<T>::value
+template <typename T> struct hb_match_reference { typedef T type; enum { value = false }; };
+template <typename T> struct hb_match_reference<T &> { typedef T type; enum { value = true }; };
+#define hb_remove_reference(T) typename hb_match_reference<T>::type
+#define hb_is_reference(T) hb_match_reference<T>::value
+template <typename T> struct hb_match_pointer { typedef T type; enum { value = false }; };
+template <typename T> struct hb_match_pointer<T *> { typedef T type; enum { value = true }; };
+#define hb_remove_pointer(T) typename hb_match_pointer<T>::type
+#define hb_is_pointer(T) hb_match_pointer<T>::value
+
+
+/* Void! For when we need a expression-type of void. */
+struct hb_void_t { typedef void value; };
+
+/* Bool! For when we need to evaluate type-dependent expressions
+ * in a template argument. */
+template <bool b> struct hb_bool_tt { enum { value = b }; };
+typedef hb_bool_tt<true> hb_true_t;
+typedef hb_bool_tt<false> hb_false_t;
+
+
+template<bool B, typename T = void>
+struct hb_enable_if {};
+
+template<typename T>
+struct hb_enable_if<true, T> { typedef T type; };
+
+#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
+
+
+/*
+ * Meta-functions.
+ */
+
+template <typename T> struct hb_is_signed;
+template <> struct hb_is_signed<signed char> { enum { value = true }; };
+template <> struct hb_is_signed<signed short> { enum { value = true }; };
+template <> struct hb_is_signed<signed int> { enum { value = true }; };
+template <> struct hb_is_signed<signed long> { enum { value = true }; };
+template <> struct hb_is_signed<unsigned char> { enum { value = false }; };
+template <> struct hb_is_signed<unsigned short> { enum { value = false }; };
+template <> struct hb_is_signed<unsigned int> { enum { value = false }; };
+template <> struct hb_is_signed<unsigned long> { enum { value = false }; };
+/* We need to define hb_is_signed for the typedefs we use on pre-Visual
+ * Studio 2010 for the int8_t type, since __int8/__int64 is not considered
+ * the same as char/long. The previous lines will suffice for the other
+ * types, though. Note that somehow, unsigned __int8 is considered same
+ * as unsigned char.
+ * https://github.com/harfbuzz/harfbuzz/pull/1499
+ */
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+template <> struct hb_is_signed<__int8> { enum { value = true }; };
+#endif
+#define hb_is_signed(T) hb_is_signed<T>::value
+
+template <bool is_signed> struct hb_signedness_int;
+template <> struct hb_signedness_int<false> { typedef unsigned int value; };
+template <> struct hb_signedness_int<true> { typedef signed int value; };
+#define hb_signedness_int(T) hb_signedness_int<T>::value
+
+
+#endif /* HB_META_HH */
diff --git a/src/hb-null.hh b/src/hb-null.hh
index 204c2fe..7421527 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -28,6 +28,7 @@
#define HB_NULL_HH
#include "hb.hh"
+#include "hb-meta.hh"
/*
@@ -45,18 +46,16 @@
* https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
*/
-template<bool> struct _hb_bool_type {};
-
template <typename T, typename B>
struct _hb_null_size
{ enum { value = sizeof (T) }; };
template <typename T>
-struct _hb_null_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
+struct _hb_null_size<T, hb_bool_tt<true || sizeof (T::min_size)> >
{ enum { value = T::null_size }; };
template <typename T>
struct hb_null_size
-{ enum { value = _hb_null_size<T, _hb_bool_type<true> >::value }; };
+{ enum { value = _hb_null_size<T, hb_true_t>::value }; };
#define hb_null_size(T) hb_null_size<T>::value
/* These doesn't belong here, but since is copy/paste from above, put it here. */
@@ -68,12 +67,12 @@
struct _hb_static_size
{ enum { value = sizeof (T) }; };
template <typename T>
-struct _hb_static_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
+struct _hb_static_size<T, hb_bool_tt<true || sizeof (T::min_size)> >
{ enum { value = T::static_size }; };
template <typename T>
struct hb_static_size
-{ enum { value = _hb_static_size<T, _hb_bool_type<true> >::value }; };
+{ enum { value = _hb_static_size<T, hb_true_t>::value }; };
#define hb_static_size(T) hb_static_size<T>::value
@@ -85,15 +84,15 @@
struct _hb_assign
{ static inline void value (T &o, const V v) { o = v; } };
template <typename T, typename V>
-struct _hb_assign<T, V, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
+struct _hb_assign<T, V, hb_bool_tt<true || sizeof (T::min_size)> >
{ static inline void value (T &o, const V v) { o.set (v); } };
template <typename T>
-struct _hb_assign<T, T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
+struct _hb_assign<T, T, hb_bool_tt<true || sizeof (T::min_size)> >
{ static inline void value (T &o, const T v) { o = v; } };
template <typename T, typename V>
static inline void hb_assign (T &o, const V v)
-{ _hb_assign<T, V, _hb_bool_type<true> >::value (o, v); }
+{ _hb_assign<T, V, hb_true_t>::value (o, v); }
/*
@@ -112,7 +111,7 @@
template <typename QType>
struct NullHelper
{
- typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
+ typedef hb_remove_const (hb_remove_reference (QType)) Type;
static const Type & get_null () { return Null<Type> (); }
};
#define Null(Type) NullHelper<Type>::get_null ()
@@ -161,7 +160,7 @@
template <typename QType>
struct CrapHelper
{
- typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
+ typedef hb_remove_const (hb_remove_reference (QType)) Type;
static Type & get_crap () { return Crap<Type> (); }
};
#define Crap(Type) CrapHelper<Type>::get_crap ()
@@ -184,7 +183,7 @@
template <typename P>
struct hb_nonnull_ptr_t
{
- typedef typename hb_remove_pointer (P) T;
+ typedef hb_remove_pointer (P) T;
hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {}
T * operator = (T *v_) { return v = v_; }
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index 6abb898..453b4fb 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -52,17 +52,14 @@
* Int types
*/
-template <bool is_signed> struct hb_signedness_int;
-template <> struct hb_signedness_int<false> { typedef unsigned int value; };
-template <> struct hb_signedness_int<true> { typedef signed int value; };
-
/* Integer types in big-endian order and no alignment requirement */
template <typename Type, unsigned int Size>
struct IntType
{
typedef Type type;
- typedef typename hb_signedness_int<hb_is_signed<Type>::value>::value wide_type;
+ typedef typename hb_signedness_int (hb_is_signed (Type)) wide_type;
+ //TODO(C++11)IntType<Type, Size>& operator = (wide_type v) { set (v); return *this; }
void set (wide_type i) { v.set (i); }
operator wide_type () const { return v; }
bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
@@ -155,7 +152,7 @@
};
/* Glyph index number, same as uint16 (length = 16 bits) */
-typedef HBUINT16 GlyphID;
+struct GlyphID : HBUINT16 {};
/* Script/language-system/feature index */
struct Index : HBUINT16 {
@@ -532,12 +529,18 @@
unsigned int get_size () const
{ return len.static_size + len * Type::static_size; }
- hb_array_t<Type> as_array ()
- { return hb_array (arrayZ, len); }
- hb_array_t<const Type> as_array () const
- { return hb_array (arrayZ, len); }
- operator hb_array_t<Type> (void) { return as_array (); }
- operator hb_array_t<const Type> (void) const { return as_array (); }
+ explicit_operator bool () const { return len; }
+
+ hb_array_t< Type> as_array () { return hb_array (arrayZ, len); }
+ hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
+
+ /* Iterator. */
+ typedef hb_array_t<const Type> iter_t;
+ typedef hb_array_t< Type> writer_t;
+ iter_t iter () const { return as_array (); }
+ writer_t writer () { return as_array (); }
+ operator iter_t () const { return iter (); }
+ operator writer_t () { return writer (); }
hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
{ return as_array ().sub_array (start_offset, count);}
@@ -556,13 +559,17 @@
if (unlikely (!c->extend (*this))) return_trace (false);
return_trace (true);
}
- template <typename T>
- bool serialize (hb_serialize_context_t *c, hb_array_t<const T> items)
+ template <typename Iterator,
+ hb_enable_if (hb_is_iterator_of (Iterator, const Type))>
+ bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
- if (unlikely (!serialize (c, items.length))) return_trace (false);
- for (unsigned int i = 0; i < items.length; i++)
- hb_assign (arrayZ[i], items[i]);
+ unsigned count = items.len ();
+ if (unlikely (!serialize (c, count))) return_trace (false);
+ /* TODO Umm. Just exhaust the iterator instead? Being extra
+ * cautious right now.. */
+ for (unsigned i = 0; i < count; i++, items++)
+ hb_assign (arrayZ[i], *items);
return_trace (true);
}
@@ -797,22 +804,42 @@
template <typename Type, typename LenType=HBUINT16>
struct SortedArrayOf : ArrayOf<Type, LenType>
{
- hb_sorted_array_t<Type> as_array ()
- { return hb_sorted_array (this->arrayZ, this->len); }
- hb_sorted_array_t<const Type> as_array () const
- { return hb_sorted_array (this->arrayZ, this->len); }
- operator hb_sorted_array_t<Type> () { return as_array (); }
- operator hb_sorted_array_t<const Type> () const { return as_array (); }
+ hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); }
+ hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
+ /* Iterator. */
+ typedef hb_sorted_array_t<const Type> iter_t;
+ typedef hb_sorted_array_t< Type> writer_t;
+ iter_t iter () const { return as_array (); }
+ writer_t writer () { return as_array (); }
+ operator iter_t () const { return iter (); }
+ operator writer_t () { return writer (); }
+
+ hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
{ return as_array ().sub_array (start_offset, count);}
- hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
+ hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
{ return as_array ().sub_array (start_offset, count);}
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
+ hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
{ return as_array ().sub_array (start_offset, count);}
- hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
+ hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
{ return as_array ().sub_array (start_offset, count);}
+ bool serialize (hb_serialize_context_t *c, unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+ bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
+ return_trace (ret);
+ }
+ template <typename Iterator,
+ hb_enable_if (hb_is_sorted_iterator_of (Iterator, const Type))>
+ bool serialize (hb_serialize_context_t *c, Iterator items)
+ {
+ TRACE_SERIALIZE (this);
+ bool ret = ArrayOf<Type, LenType>::serialize (c, items);
+ return_trace (ret);
+ }
+
+
template <typename T>
Type &bsearch (const T &x, Type ¬_found = Crap (Type))
{ return *as_array ().bsearch (x, ¬_found); }
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 0526c35..3846d46 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -83,7 +83,7 @@
bool serialize (hb_serialize_context_t *c,
const hb_subset_plan_t *plan,
- const hb_vector_t<segment_plan> &segments)
+ const hb_sorted_vector_t<segment_plan> &segments)
{
TRACE_SERIALIZE (this);
@@ -154,7 +154,7 @@
return_trace (true);
}
- static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
+ static size_t get_sub_table_size (const hb_sorted_vector_t<segment_plan> &segments)
{
size_t segment_size = 0;
for (unsigned int i = 0; i < segments.length; i++)
@@ -177,7 +177,7 @@
}
static bool create_sub_table_plan (const hb_subset_plan_t *plan,
- hb_vector_t<segment_plan> *segments)
+ hb_sorted_vector_t<segment_plan> *segments)
{
segment_plan *segment = nullptr;
hb_codepoint_t last_gid = 0;
@@ -491,7 +491,7 @@
}
bool serialize (hb_serialize_context_t *c,
- const hb_vector_t<CmapSubtableLongGroup> &group_data)
+ const hb_sorted_vector_t<CmapSubtableLongGroup> &group_data)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
@@ -519,7 +519,7 @@
bool serialize (hb_serialize_context_t *c,
- const hb_vector_t<CmapSubtableLongGroup> &groups)
+ const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
{
if (unlikely (!c->extend_min (*this))) return false;
@@ -530,13 +530,13 @@
return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
}
- static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
+ static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups)
{
return 16 + 12 * groups.length;
}
static bool create_sub_table_plan (const hb_subset_plan_t *plan,
- hb_vector_t<CmapSubtableLongGroup> *groups)
+ hb_sorted_vector_t<CmapSubtableLongGroup> *groups)
{
CmapSubtableLongGroup *group = nullptr;
@@ -853,8 +853,8 @@
+ CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
}
- hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
- hb_vector_t<CmapSubtableLongGroup> format12_groups;
+ hb_sorted_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
+ hb_sorted_vector_t<CmapSubtableLongGroup> format12_groups;
};
bool _create_plan (const hb_subset_plan_t *plan,
diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh
index 39a8bba..c163140 100644
--- a/src/hb-ot-layout-common.hh
+++ b/src/hb-ot-layout-common.hh
@@ -66,7 +66,6 @@
#define NOT_COVERED ((unsigned int) -1)
-
/*
*
* OpenType Layout Common Table Formats
@@ -826,8 +825,9 @@
return i;
}
- bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs)
+ template <typename Iterator,
+ hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
+ bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
return_trace (glyphArray.serialize (c, glyphs));
@@ -853,19 +853,17 @@
template <typename set_t>
bool add_coverage (set_t *glyphs) const
- {
- return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
- }
+ { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
public:
/* Older compilers need this to be public. */
- struct Iter {
+ struct iter_t
+ {
void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
void fini () {}
- bool more () { return i < c->glyphArray.len; }
+ bool more () const { return i < c->glyphArray.len; }
void next () { i++; }
- hb_codepoint_t get_glyph () { return c->glyphArray[i]; }
- unsigned int get_coverage () { return i; }
+ hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
private:
const struct CoverageFormat1 *c;
@@ -894,20 +892,23 @@
NOT_COVERED;
}
- bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs)
+ template <typename Iterator,
+ hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
+ bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- if (unlikely (!glyphs.length))
+ if (unlikely (!glyphs))
{
rangeRecord.len.set (0);
return_trace (true);
}
+ /* TODO(iter) Port to non-random-access iterator interface. */
+ unsigned int count = glyphs.len ();
unsigned int num_ranges = 1;
- for (unsigned int i = 1; i < glyphs.length; i++)
+ for (unsigned int i = 1; i < count; i++)
if (glyphs[i - 1] + 1 != glyphs[i])
num_ranges++;
rangeRecord.len.set (num_ranges);
@@ -916,7 +917,7 @@
unsigned int range = 0;
rangeRecord[range].start = glyphs[0];
rangeRecord[range].value.set (0);
- for (unsigned int i = 1; i < glyphs.length; i++)
+ for (unsigned int i = 1; i < count; i++)
{
if (glyphs[i - 1] + 1 != glyphs[i])
{
@@ -972,7 +973,7 @@
public:
/* Older compilers need this to be public. */
- struct Iter
+ struct iter_t
{
void init (const CoverageFormat2 &c_)
{
@@ -987,7 +988,7 @@
}
}
void fini () {}
- bool more () { return i < c->rangeRecord.len; }
+ bool more () const { return i < c->rangeRecord.len; }
void next ()
{
if (j >= c->rangeRecord[i].end)
@@ -995,23 +996,25 @@
i++;
if (more ())
{
- hb_codepoint_t old = j;
+ unsigned int old = coverage;
j = c->rangeRecord[i].start;
- if (unlikely (j <= old))
+ coverage = c->rangeRecord[i].value;
+ if (unlikely (coverage != old + 1))
{
- /* Broken table. Skip. Important to avoid DoS. */
+ /* Broken table. Skip. Important to avoid DoS.
+ * Also, our callers depend on coverage being
+ * consecutive and monotonically increasing,
+ * ie. iota(). */
i = c->rangeRecord.len;
return;
}
- coverage = c->rangeRecord[i].value;
}
return;
}
coverage++;
j++;
}
- hb_codepoint_t get_glyph () { return j; }
- unsigned int get_coverage () { return coverage; }
+ hb_codepoint_t get_glyph () const { return j; }
private:
const struct CoverageFormat2 *c;
@@ -1032,6 +1035,14 @@
struct Coverage
{
+ /* Map interface. */
+ static constexpr unsigned SENTINEL = NOT_COVERED;
+ typedef unsigned int value_t;
+ value_t operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator () (hb_codepoint_t k) const { return has (k); }
+
+ unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
switch (u.format) {
@@ -1041,17 +1052,20 @@
}
}
- bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs)
+ template <typename Iterator,
+ hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
+ bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
+ /* TODO(iter) Port to non-random-access iterator interface. */
+ unsigned int count = glyphs.len ();
unsigned int num_ranges = 1;
- for (unsigned int i = 1; i < glyphs.length; i++)
+ for (unsigned int i = 1; i < count; i++)
if (glyphs[i - 1] + 1 != glyphs[i])
num_ranges++;
- u.format.set (glyphs.length * 2 < num_ranges * 3 ? 1 : 2);
+ u.format.set (count * 2 < num_ranges * 3 ? 1 : 2);
switch (u.format)
{
@@ -1105,9 +1119,12 @@
}
}
- struct Iter
+ struct iter_t :
+ hb_iter_t<iter_t, hb_codepoint_t>,
+ hb_iter_mixin_t<iter_t, hb_codepoint_t>
{
- Iter (const Coverage &c_)
+ static constexpr bool is_sorted_iterator = true;
+ iter_t (const Coverage &c_ = Null(Coverage))
{
memset (this, 0, sizeof (*this));
format = c_.u.format;
@@ -1118,7 +1135,7 @@
default: return;
}
}
- bool more ()
+ bool __more__ () const
{
switch (format)
{
@@ -1127,7 +1144,7 @@
default:return false;
}
}
- void next ()
+ void __next__ ()
{
switch (format)
{
@@ -1136,7 +1153,10 @@
default: break;
}
}
- hb_codepoint_t get_glyph ()
+ typedef hb_codepoint_t __item_t__;
+ __item_t__ __item__ () const { return get_glyph (); }
+
+ hb_codepoint_t get_glyph () const
{
switch (format)
{
@@ -1145,23 +1165,15 @@
default:return 0;
}
}
- unsigned int get_coverage ()
- {
- switch (format)
- {
- case 1: return u.format1.get_coverage ();
- case 2: return u.format2.get_coverage ();
- default:return -1;
- }
- }
private:
unsigned int format;
union {
- CoverageFormat2::Iter format2; /* Put this one first since it's larger; helps shut up compiler. */
- CoverageFormat1::Iter format1;
+ CoverageFormat2::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
+ CoverageFormat1::iter_t format1;
} u;
};
+ iter_t iter () const { return iter_t (*this); }
protected:
union {
@@ -1193,13 +1205,13 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const HBUINT16> glyphs,
+ hb_array_t<const GlyphID> glyphs,
hb_array_t<const HBUINT16> klasses)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- if (unlikely (!glyphs.length))
+ if (unlikely (!glyphs))
{
startGlyph.set (0);
classValue.len.set (0);
@@ -1224,22 +1236,22 @@
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset;
const hb_map_t &glyph_map = *c->plan->glyph_map;
- hb_vector_t<GlyphID> glyphs;
+ hb_sorted_vector_t<GlyphID> glyphs;
hb_vector_t<HBUINT16> klasses;
hb_codepoint_t start = startGlyph;
hb_codepoint_t end = start + classValue.len;
for (hb_codepoint_t g = start; g < end; g++)
{
+ if (!glyphset.has (g)) continue;
unsigned int value = classValue[g - start];
if (!value) continue;
- if (!glyphset.has (g)) continue;
glyphs.push()->set (glyph_map[g]);
klasses.push()->set (value);
}
c->serializer->propagate_error (glyphs, klasses);
ClassDef_serialize (c->serializer, glyphs, klasses);
- return_trace (glyphs.length);
+ return_trace ((bool) glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1329,13 +1341,13 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const HBUINT16> glyphs,
+ hb_array_t<const GlyphID> glyphs,
hb_array_t<const HBUINT16> klasses)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- if (unlikely (!glyphs.length))
+ if (unlikely (!glyphs))
{
rangeRecord.len.set (0);
return_trace (true);
@@ -1390,7 +1402,7 @@
}
c->serializer->propagate_error (glyphs, klasses);
ClassDef_serialize (c->serializer, glyphs, klasses);
- return_trace (glyphs.length);
+ return_trace ((bool) glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1468,6 +1480,14 @@
struct ClassDef
{
+ /* Map interface. */
+ static constexpr unsigned SENTINEL = 0;
+ typedef unsigned int value_t;
+ value_t operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator () (hb_codepoint_t k) const { return has (k); }
+
+ unsigned int get (hb_codepoint_t k) const { return get_class (k); }
unsigned int get_class (hb_codepoint_t glyph_id) const
{
switch (u.format) {
@@ -1485,7 +1505,7 @@
if (unlikely (!c->extend_min (*this))) return_trace (false);
unsigned int format = 2;
- if (glyphs.length)
+ if (likely (glyphs))
{
hb_codepoint_t glyph_min = glyphs[0];
hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index e17a282..485458a 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -722,15 +722,11 @@
{
bool intersects (const hb_set_t *glyphs) const
{
- unsigned int count = pairSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (glyphs->has (iter.get_glyph ()) &&
- (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
+ for (auto it = hb_zip (this+coverage, pairSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ if ((this+*it).intersects (glyphs, valueFormat))
return true;
- }
return false;
}
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 33b8f0e..1b60ce2 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -36,7 +36,7 @@
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const GlyphID> substitutes);
struct SingleSubstFormat1
@@ -46,26 +46,16 @@
void closure (hb_closure_context_t *c) const
{
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- /* TODO Switch to range-based API to work around malicious fonts.
- * https://github.com/harfbuzz/harfbuzz/issues/363 */
- hb_codepoint_t glyph_id = iter.get_glyph ();
- if (c->glyphs->has (glyph_id))
- c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
- }
+ for (auto it = hb_iter (this+coverage)
+ | hb_filter (*c->glyphs); it; ++it)
+ c->output->add ((*it + deltaGlyphID) & 0xFFFFu);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- /* TODO Switch to range-based API to work around malicious fonts.
- * https://github.com/harfbuzz/harfbuzz/issues/363 */
- hb_codepoint_t glyph_id = iter.get_glyph ();
- c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
- }
+ for (auto it = hb_iter (this+coverage); it; ++it)
+ c->output->add ((*it + deltaGlyphID) & 0xFFFFu);
}
const Coverage &get_coverage () const { return this+coverage; }
@@ -92,7 +82,7 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
int delta)
{
TRACE_SERIALIZE (this);
@@ -107,14 +97,14 @@
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset;
const hb_map_t &glyph_map = *c->plan->glyph_map;
- hb_vector_t<GlyphID> from;
+ hb_sorted_vector_t<GlyphID> from;
hb_vector_t<GlyphID> to;
hb_codepoint_t delta = deltaGlyphID;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
+ for (auto it = hb_iter (this+coverage)
+ | hb_filter (glyphset); it; ++it)
{
- if (!glyphset.has (iter.get_glyph ())) continue;
- from.push ()->set (glyph_map[iter.get_glyph ()]);
- to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
+ from.push ()->set (glyph_map[*it]);
+ to.push ()->set (glyph_map[(*it + delta) & 0xFFFF]);
}
c->serializer->propagate_error (from, to);
SingleSubst_serialize (c->serializer, from, to);
@@ -145,26 +135,18 @@
void closure (hb_closure_context_t *c) const
{
- unsigned int count = substitute.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- c->out->add (substitute[iter.get_coverage ()]);
- }
+ for (auto it = hb_zip (this+coverage, substitute)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ c->output->add (*it);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- unsigned int count = substitute.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- c->output->add (substitute[iter.get_coverage ()]);
- }
+ for (auto it = hb_zip (this+coverage, substitute)
+ | hb_map (hb_second); it; ++it)
+ c->output->add (*it);
}
const Coverage &get_coverage () const { return this+coverage; }
@@ -189,7 +171,7 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const GlyphID> substitutes)
{
TRACE_SERIALIZE (this);
@@ -204,13 +186,13 @@
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset;
const hb_map_t &glyph_map = *c->plan->glyph_map;
- hb_vector_t<GlyphID> from;
+ hb_sorted_vector_t<GlyphID> from;
hb_vector_t<GlyphID> to;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
+ for (auto it = hb_zip (this+coverage, substitute)
+ | hb_filter (glyphset, hb_first); it; ++it)
{
- if (!glyphset.has (iter.get_glyph ())) continue;
- from.push ()->set (glyph_map[iter.get_glyph ()]);
- to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
+ from.push ()->set (glyph_map[it->first]);
+ to.push ()->set (glyph_map[it->second]);
}
c->serializer->propagate_error (from, to);
SingleSubst_serialize (c->serializer, from, to);
@@ -238,7 +220,7 @@
struct SingleSubst
{
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const GlyphID> substitutes)
{
TRACE_SERIALIZE (this);
@@ -286,7 +268,7 @@
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const GlyphID> substitutes)
{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
@@ -296,7 +278,7 @@
{
unsigned int count = substitute.len;
for (unsigned int i = 0; i < count; i++)
- c->out->add (substitute[i]);
+ c->output->add (substitute[i]);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -335,10 +317,10 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs)
+ hb_array_t<const GlyphID> subst)
{
TRACE_SERIALIZE (this);
- return_trace (substitute.serialize (c, glyphs));
+ return_trace (substitute.serialize (c, subst));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -361,22 +343,18 @@
void closure (hb_closure_context_t *c) const
{
- unsigned int count = sequence.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- (this+sequence[iter.get_coverage ()]).closure (c);
- }
+ for (auto it = hb_zip (this+coverage, sequence)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).closure (c);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- unsigned int count = sequence.len;
- for (unsigned int i = 0; i < count; i++)
- (this+sequence[i]).collect_glyphs (c);
+ for (auto it = hb_zip (this+coverage, sequence)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).collect_glyphs (c);
}
const Coverage &get_coverage () const { return this+coverage; }
@@ -398,7 +376,7 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const GlyphID> substitute_glyphs_list)
{
@@ -444,7 +422,7 @@
struct MultipleSubst
{
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const GlyphID> substitute_glyphs_list)
{
@@ -482,7 +460,7 @@
{
unsigned int count = alternates.len;
for (unsigned int i = 0; i < count; i++)
- c->out->add (alternates[i]);
+ c->output->add (alternates[i]);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -514,10 +492,10 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs)
+ hb_array_t<const GlyphID> alts)
{
TRACE_SERIALIZE (this);
- return_trace (alternates.serialize (c, glyphs));
+ return_trace (alternates.serialize (c, alts));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -541,26 +519,17 @@
void closure (hb_closure_context_t *c) const
{
- unsigned int count = alternateSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- (this+alternateSet[iter.get_coverage ()]).closure (c);
- }
+ for (auto it = hb_zip (this+coverage, alternateSet)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).closure (c);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- unsigned int count = alternateSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
- }
+ for (auto it = hb_zip (this+coverage, alternateSet)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).collect_glyphs (c);
}
const Coverage &get_coverage () const { return this+coverage; }
@@ -582,7 +551,7 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
hb_array_t<const GlyphID> alternate_glyphs_list)
{
@@ -628,7 +597,7 @@
struct AlternateSubst
{
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
hb_array_t<const GlyphID> alternate_glyphs_list)
{
@@ -678,7 +647,7 @@
for (unsigned int i = 1; i < count; i++)
if (!c->glyphs->has (component[i]))
return;
- c->out->add (ligGlyph);
+ c->output->add (ligGlyph);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -857,40 +826,28 @@
{
bool intersects (const hb_set_t *glyphs) const
{
- unsigned int count = ligatureSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (glyphs->has (iter.get_glyph ()) &&
- (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
- return true;
- }
+ for (auto it = hb_zip (this+coverage, ligatureSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ if ((this+*it).intersects (glyphs))
+ return true;
return false;
}
void closure (hb_closure_context_t *c) const
{
- unsigned int count = ligatureSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- (this+ligatureSet[iter.get_coverage ()]).closure (c);
- }
+ for (auto it = hb_zip (this+coverage, ligatureSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).closure (c);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- unsigned int count = ligatureSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
- }
+ for (auto it = hb_zip (this+coverage, ligatureSet)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).collect_glyphs (c);
}
const Coverage &get_coverage () const { return this+coverage; }
@@ -917,7 +874,7 @@
}
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> first_glyphs,
+ hb_sorted_array_t<const GlyphID> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
hb_array_t<const GlyphID> ligatures_list,
hb_array_t<const unsigned int> component_count_list,
@@ -968,7 +925,7 @@
struct LigatureSubst
{
bool serialize (hb_serialize_context_t *c,
- hb_array_t<const GlyphID> first_glyphs,
+ hb_sorted_array_t<const GlyphID> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
hb_array_t<const GlyphID> ligatures_list,
hb_array_t<const unsigned int> component_count_list,
@@ -1061,14 +1018,10 @@
return;
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
- count = substitute.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- c->out->add (substitute[iter.get_coverage ()]);
- }
+ for (auto it = hb_zip (this+coverage, substitute)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ c->output->add (*it);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1320,7 +1273,7 @@
bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const GlyphID> substitutes)
{
TRACE_SERIALIZE (this);
@@ -1330,7 +1283,7 @@
bool serialize_multiple (hb_serialize_context_t *c,
uint32_t lookup_props,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const GlyphID> substitute_glyphs_list)
{
@@ -1344,7 +1297,7 @@
bool serialize_alternate (hb_serialize_context_t *c,
uint32_t lookup_props,
- hb_array_t<const GlyphID> glyphs,
+ hb_sorted_array_t<const GlyphID> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
hb_array_t<const GlyphID> alternate_glyphs_list)
{
@@ -1358,7 +1311,7 @@
bool serialize_ligature (hb_serialize_context_t *c,
uint32_t lookup_props,
- hb_array_t<const GlyphID> first_glyphs,
+ hb_sorted_array_t<const GlyphID> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
hb_array_t<const GlyphID> ligatures_list,
hb_array_t<const unsigned int> component_count_list,
@@ -1380,7 +1333,7 @@
static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
{
if (!c->should_visit_lookup (lookup_index))
- return HB_VOID;
+ return hb_void_t ();
hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
index 88d834d..4b10e4d 100644
--- a/src/hb-ot-layout-gsubgpos.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -64,8 +64,8 @@
const char *get_name () { return "CLOSURE"; }
typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
template <typename T>
- return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
- static return_t default_return_value () { return HB_VOID; }
+ return_t dispatch (const T &obj) { obj.closure (this); return hb_void_t (); }
+ static return_t default_return_value () { return hb_void_t (); }
void recurse (unsigned int lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
@@ -92,7 +92,7 @@
hb_face_t *face;
hb_set_t *glyphs;
- hb_set_t out[1];
+ hb_set_t output[1];
recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int debug_depth;
@@ -114,8 +114,8 @@
void flush ()
{
- hb_set_union (glyphs, out);
- hb_set_clear (out);
+ hb_set_union (glyphs, output);
+ hb_set_clear (output);
}
private:
@@ -156,8 +156,8 @@
const char *get_name () { return "COLLECT_GLYPHS"; }
typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
template <typename T>
- return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
- static return_t default_return_value () { return HB_VOID; }
+ return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_void_t (); }
+ static return_t default_return_value () { return hb_void_t (); }
void recurse (unsigned int lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
@@ -652,9 +652,9 @@
{
hb_applicable_t *entry = array.push();
entry->init (obj, apply_to<T>);
- return HB_VOID;
+ return hb_void_t ();
}
- static return_t default_return_value () { return HB_VOID; }
+ static return_t default_return_value () { return hb_void_t (); }
hb_get_subtables_context_t (array_t &array_) :
array (array_),
@@ -1436,16 +1436,11 @@
{intersects_glyph},
nullptr
};
-
- unsigned int count = ruleSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (glyphs->has (iter.get_glyph ()) &&
- (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+ for (auto it = hb_zip (this+coverage, ruleSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ if ((this+*it).intersects (glyphs, lookup_context))
return true;
- }
return false;
}
@@ -1455,15 +1450,10 @@
{intersects_glyph},
nullptr
};
-
- unsigned int count = ruleSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
- }
+ for (auto it = hb_zip (this+coverage, ruleSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).closure (c, lookup_context);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -2089,16 +2079,11 @@
{intersects_glyph},
{nullptr, nullptr, nullptr}
};
-
- unsigned int count = ruleSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (glyphs->has (iter.get_glyph ()) &&
- (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+ for (auto it = hb_zip (this+coverage, ruleSet)
+ | hb_filter (*glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ if ((this+*it).intersects (glyphs, lookup_context))
return true;
- }
return false;
}
@@ -2108,15 +2093,10 @@
{intersects_glyph},
{nullptr, nullptr, nullptr}
};
-
- unsigned int count = ruleSet.len;
- for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
- {
- if (unlikely (iter.get_coverage () >= count))
- break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (iter.get_glyph ()))
- (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
- }
+ for (auto it = hb_zip (this+coverage, ruleSet)
+ | hb_filter (*c->glyphs, hb_first)
+ | hb_map (hb_second); it; ++it)
+ (this+*it).closure (c, lookup_context);
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
diff --git a/src/hb-ot-map.hh b/src/hb-ot-map.hh
index 28407c2..132da55 100644
--- a/src/hb-ot-map.hh
+++ b/src/hb-ot-map.hh
@@ -167,7 +167,7 @@
hb_mask_t global_mask;
- hb_vector_t<feature_map_t> features;
+ hb_sorted_vector_t<feature_map_t> features;
hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
hb_vector_t<stage_map_t> stages[2]; /* GSUB/GPOS */
};
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index 2a1f2f8..471a201 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -77,7 +77,9 @@
/* Bubble-sort or something equally good!
* May not be good-enough for presidential candidate interviews, but good-enough for us... */
- hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]);
+ hb_stable_sort (&glyphs[0], num_glyphs,
+ (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::GlyphID::cmp,
+ &substitutes[0]);
/* Each glyph takes four bytes max, and there's some overhead. */
@@ -86,7 +88,7 @@
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
bool ret = lookup->serialize_single (&c,
OT::LookupFlag::IgnoreMarks,
- hb_array (glyphs, num_glyphs),
+ hb_sorted_array (glyphs, num_glyphs),
hb_array (substitutes, num_glyphs));
c.end_serialize ();
/* TODO sanitize the results? */
@@ -123,7 +125,9 @@
first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
num_first_glyphs++;
}
- hb_stable_sort (&first_glyphs[0], num_first_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+ hb_stable_sort (&first_glyphs[0], num_first_glyphs,
+ (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::GlyphID::cmp,
+ &first_glyphs_indirection[0]);
/* Now that the first-glyphs are sorted, walk again, populate ligatures. */
for (unsigned int i = 0; i < num_first_glyphs; i++)
@@ -159,7 +163,7 @@
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
bool ret = lookup->serialize_ligature (&c,
OT::LookupFlag::IgnoreMarks,
- hb_array (first_glyphs, num_first_glyphs),
+ hb_sorted_array (first_glyphs, num_first_glyphs),
hb_array (ligature_per_first_glyph_count_list, num_first_glyphs),
hb_array (ligature_list, num_ligatures),
hb_array (component_count_list, num_ligatures),
diff --git a/src/hb-set.hh b/src/hb-set.hh
index 64a1363..c0f6b88 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -69,7 +69,7 @@
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
- bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); }
+ bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
@@ -186,7 +186,7 @@
hb_object_header_t header;
bool successful; /* Allocations successful */
mutable unsigned int population;
- hb_vector_t<page_map_t> page_map;
+ hb_sorted_vector_t<page_map_t> page_map;
hb_vector_t<page_t> pages;
void init_shallow ()
@@ -357,15 +357,22 @@
for (unsigned int i = a; i < b + 1; i++)
del (i);
}
- bool has (hb_codepoint_t g) const
+ bool get (hb_codepoint_t g) const
{
const page_t *page = page_for (g);
if (!page)
return false;
- return page->has (g);
+ return page->get (g);
}
- bool intersects (hb_codepoint_t first,
- hb_codepoint_t last) const
+
+ /* Map interface. */
+ static constexpr bool SENTINEL = false;
+ typedef bool value_t;
+ value_t operator [] (hb_codepoint_t k) const { return get (k); }
+ bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+ bool operator () (hb_codepoint_t k) const { return has (k); }
+
+ bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;
return next (&c) && c <= last;
@@ -671,27 +678,28 @@
/*
* Iterator implementation.
*/
- struct const_iter_t : hb_sorted_iter_t<const_iter_t, const hb_codepoint_t>
+ struct iter_t :
+ hb_iter_t<iter_t, hb_codepoint_t>,
+ hb_iter_mixin_t<iter_t, hb_codepoint_t>
{
- const_iter_t (const hb_set_t &s_) :
- s (s_), v (INVALID), l (s.get_population () + 1) { __next__ (); }
+ static constexpr bool is_sorted_iterator = true;
+ iter_t (const hb_set_t &s_ = Null(hb_set_t)) :
+ s (&s_), v (INVALID), l (s->get_population () + 1) { __next__ (); }
- typedef hb_codepoint_t __item_type__;
+ typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; }
- void __next__ () { s.next (&v); if (l) l--; }
- void __prev__ () { s.previous (&v); }
- unsigned __len__ () { return l; }
+ void __next__ () { s->next (&v); if (l) l--; }
+ void __prev__ () { s->previous (&v); }
+ unsigned __len__ () const { return l; }
protected:
- const hb_set_t &s;
+ const hb_set_t *s;
hb_codepoint_t v;
unsigned l;
};
- const_iter_t const_iter () const { return const_iter_t (*this); }
- operator const_iter_t () const { return const_iter (); }
- typedef const_iter_t iter_t;
- iter_t iter () const { return const_iter (); }
+ iter_t iter () const { return iter_t (*this); }
+ operator iter_t () const { return iter (); }
protected:
diff --git a/src/hb-vector.hh b/src/hb-vector.hh
index 2fd739b..00f4479 100644
--- a/src/hb-vector.hh
+++ b/src/hb-vector.hh
@@ -89,10 +89,16 @@
explicit_operator bool () const { return 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< Type> as_array () { return hb_array (arrayZ(), length); }
+ hb_array_t<const Type> as_array () const { return hb_array (arrayZ(), length); }
+
+ /* Iterator. */
+ typedef hb_array_t<const Type> iter_t;
+ typedef hb_array_t< Type> writer_t;
+ iter_t iter () const { return as_array (); }
+ writer_t writer () { return as_array (); }
+ operator iter_t () const { return iter (); }
+ operator writer_t () { return writer (); }
hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
{ return as_array ().sub_array (start_offset, count);}
@@ -108,19 +114,8 @@
hb_sorted_array_t<const Type> as_sorted_array () const
{ return hb_sorted_array (arrayZ(), length); }
- hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int count) const
- { return as_sorted_array ().sorted_sub_array (start_offset, count);}
- hb_array_t<const Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
- { return as_sorted_array ().sorted_sub_array (start_offset, count);}
- hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int count)
- { return as_sorted_array ().sorted_sub_array (start_offset, count);}
- hb_array_t<Type> sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
- { return as_sorted_array ().sorted_sub_array (start_offset, count);}
-
template <typename T> explicit_operator T * () { return arrayZ(); }
template <typename T> explicit_operator const T * () const { return arrayZ(); }
- operator hb_array_t<Type> () { return as_array (); }
- operator hb_array_t<const Type> () const { return as_array (); }
Type * operator + (unsigned int i) { return arrayZ() + i; }
const Type * operator + (unsigned int i) const { return arrayZ() + i; }
@@ -242,19 +237,34 @@
template <typename T>
const Type *lsearch (const T &x, const Type *not_found = nullptr) const
{ return as_array ().lsearch (x, not_found); }
+};
+
+template <typename Type>
+struct hb_sorted_vector_t : hb_vector_t<Type>
+{
+ hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ(), this->length); }
+ hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ(), this->length); }
+
+ /* Iterator. */
+ typedef hb_sorted_array_t<const Type> const_iter_t;
+ typedef hb_sorted_array_t< Type> iter_t;
+ const_iter_t iter () const { return as_array (); }
+ const_iter_t citer () const { return as_array (); }
+ iter_t iter () { return as_array (); }
+ operator iter_t () { return iter (); }
+ operator const_iter_t () const { return iter (); }
template <typename T>
Type *bsearch (const T &x, Type *not_found = nullptr)
- { return as_sorted_array ().bsearch (x, not_found); }
+ { return as_array ().bsearch (x, not_found); }
template <typename T>
const Type *bsearch (const T &x, const Type *not_found = nullptr) const
- { return as_sorted_array ().bsearch (x, not_found); }
+ { return as_array ().bsearch (x, not_found); }
template <typename T>
bool bfind (const T &x, unsigned int *i = nullptr,
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
- { return as_sorted_array ().bfind (x, i, not_found, to_store); }
+ { return as_array ().bfind (x, i, not_found, to_store); }
};
-
#endif /* HB_VECTOR_HH */
diff --git a/src/hb.hh b/src/hb.hh
index 5945de4..0b535af 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -626,28 +626,17 @@
#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
-/* Some really basic things everyone wants. */
-template <typename T> struct hb_remove_const { typedef T value; };
-template <typename T> struct hb_remove_const<const T> { typedef T value; };
-#define hb_remove_const(T) hb_remove_const<T>::value
-template <typename T> struct hb_remove_reference { typedef T value; };
-template <typename T> struct hb_remove_reference<T &> { typedef T value; };
-#define hb_remove_reference(T) hb_remove_reference<T>::value
-template <typename T> struct hb_remove_pointer { typedef T value; };
-template <typename T> struct hb_remove_pointer<T *> { typedef T value; };
-#define hb_remove_pointer(T) hb_remove_pointer<T>::value
-
-
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include
* them directly.*/
-#include "hb-atomic.hh"
+#include "hb-meta.hh"
#include "hb-mutex.hh"
-#include "hb-null.hh"
-#include "hb-dsalgs.hh" // Requires: hb-null
-#include "hb-iter.hh" // Requires: hb-null
-#include "hb-debug.hh" // Requires: hb-atomic hb-dsalgs
-#include "hb-array.hh" // Requires: hb-dsalgs hb-iter hb-null
+#include "hb-atomic.hh" // Requires: hb-meta
+#include "hb-null.hh" // Requires: hb-meta
+#include "hb-algs.hh" // Requires: hb-null
+#include "hb-iter.hh" // Requires: hb-algs hb-meta hb-null
+#include "hb-debug.hh" // Requires: hb-algs hb-atomic
+#include "hb-array.hh" // Requires: hb-algs hb-iter hb-null
#include "hb-vector.hh" // Requires: hb-array hb-null
#include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector
diff --git a/src/test-iter.cc b/src/test-iter.cc
index 05430b0..2b23901 100644
--- a/src/test-iter.cc
+++ b/src/test-iter.cc
@@ -29,19 +29,22 @@
#include "hb-array.hh"
#include "hb-set.hh"
+#include "hb-ot-layout-common.hh"
template <typename T>
-struct array_iter_t : hb_iter_t<array_iter_t<T>, T>, hb_iter_mixin_t<array_iter_t<T>, T>
+struct array_iter_t :
+ hb_iter_t<array_iter_t<T>, T&>,
+ hb_iter_mixin_t<array_iter_t<T>, T&>
{
array_iter_t (hb_array_t<T> arr_) : arr (arr_) {}
- typedef T __item_type__;
+ typedef T& __item_t__;
+ static constexpr bool is_random_access_iterator = true;
T& __item_at__ (unsigned i) const { return arr[i]; }
void __forward__ (unsigned n) { arr += n; }
void __rewind__ (unsigned n) { arr -= n; }
unsigned __len__ () const { return arr.length; }
- bool __random_access__ () const { return true; }
private:
hb_array_t<T> arr;
@@ -61,6 +64,36 @@
hb_array_t<T> arr;
};
+
+template <typename Iter,
+ hb_enable_if (hb_is_iterator (Iter))>
+static void
+test_iterator (Iter it)
+{
+ Iter default_constructed;
+
+ /* Iterate over a copy of it. */
+ for (auto c = it.iter (); c; c++)
+ *c;
+
+ it += it.len ();
+ it = it + 10;
+ it = 10 + it;
+
+ assert (*it == it[0]);
+
+ if (it.is_random_access_iterator) {}
+}
+
+template <typename Iterable,
+ hb_enable_if (hb_is_iterable (Iterable))>
+static void
+test_iterable (const Iterable &lst = Null(Iterable))
+{
+ // Test that can take iterator from.
+ test_iterator (lst.iter ());
+}
+
int
main (int argc, char **argv)
{
@@ -72,6 +105,8 @@
array_iter_t<const int> s2 (v); /* Implicit conversion from vector. */
array_iter_t<int> t (dst);
+ static_assert (hb_is_random_access_iterator (array_iter_t<int>), "");
+
some_array_t<const int> a (src);
s2 = s;
@@ -80,5 +115,22 @@
hb_copy (t, s);
// hb_copy (t, a.iter ());
+ test_iterable (v);
+ hb_set_t st;
+ test_iterable (st);
+ hb_sorted_array_t<int> sa;
+ test_iterable (sa);
+
+ test_iterable<hb_array_t<int> > ();
+ test_iterable<hb_sorted_array_t<const int> > ();
+ test_iterable<hb_vector_t<float> > ();
+ test_iterable<hb_set_t> ();
+ test_iterable<OT::Coverage> ();
+
+ test_iterator (hb_zip (st, v));
+
+ hb_array_t<hb_vector_t<int> > pa;
+ pa->as_array ();
+
return 0;
}