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 &not_found = Crap (Type))
   { return *as_array ().bsearch (x, &not_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;
 }