[meta] Add HB_AUTO_RETURN_EXPR, HB_VOID_RETURN_EXPR, hb_priority, hb_has(), hb_get()

The first three based on range-v3.
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index 5ee0a4c..1cda64f 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -70,6 +70,52 @@
   operator () (const T& v) const { return bool (v); }
 } HB_FUNCOBJ (hb_bool);
 
+struct
+{
+  private:
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<2>) const HB_AUTO_RETURN_EXPR (p->has (v))
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN_EXPR (p.has (v))
+
+  template <typename Pred, typename Val> auto
+  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN_EXPR (p (v))
+
+  public:
+
+  template <typename Pred, typename Val> auto
+  operator () (Pred&& p, Val &&v) const HB_AUTO_RETURN_EXPR (
+    (bool) impl (hb_forward<Pred> (p),
+		 hb_forward<Val> (v),
+		 hb_prioritize)
+  )
+} HB_FUNCOBJ (hb_has);
+
+struct
+{
+  private:
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN_EXPR (f->get (hb_forward<Val> (v)))
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN_EXPR (f.get (hb_forward<Val> (v)))
+
+  template <typename Proj, typename Val> auto
+  impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN_EXPR (f (hb_forward<Val> (v)))
+
+  public:
+
+  template <typename Proj, typename Val> auto
+  operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN_EXPR (
+    impl (hb_forward<Proj> (f),
+	  hb_forward<Val> (v),
+	  hb_prioritize)
+  )
+} HB_FUNCOBJ (hb_get);
+
 template <typename T1, typename T2>
 struct hb_pair_t
 {
diff --git a/src/hb-iter.hh b/src/hb-iter.hh
index 9829092..719987d 100644
--- a/src/hb-iter.hh
+++ b/src/hb-iter.hh
@@ -30,6 +30,7 @@
 #define HB_ITER_HH
 
 #include "hb.hh"
+#include "hb-algs.hh"
 #include "hb-meta.hh"
 
 
@@ -272,8 +273,8 @@
 
   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]); }
+  __item_t__ __item__ () const { return hb_get (f, *it); }
+  __item_t__ __item_at__ (unsigned i) const { return hb_get (f, it[i]); }
   bool __more__ () const { return bool (it); }
   unsigned __len__ () const { return it.len (); }
   void __next__ () { ++it; }
@@ -315,7 +316,7 @@
 			  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; }
+  { while (it && !hb_has (p, hb_get (f, *it))) ++it; }
 
   typedef typename Iter::item_t __item_t__;
   static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
diff --git a/src/hb-meta.hh b/src/hb-meta.hh
index d2733d7..83b0ad6 100644
--- a/src/hb-meta.hh
+++ b/src/hb-meta.hh
@@ -92,10 +92,8 @@
 
 /* Void meta-function ala std::void_t
  * https://en.cppreference.com/w/cpp/types/void_t */
-template<typename... Ts>
-struct _hb_make_void { typedef void type; };
-template<typename... Ts>
-using hb_void_tt = typename _hb_make_void<Ts...>::type;
+template<typename... Ts> struct _hb_void_tt { typedef void type; };
+template<typename... Ts> using hb_void_tt = typename _hb_void_tt<Ts...>::type;
 
 /* Bool!  For when we need to evaluate type-dependent expressions
  * in a template argument. */
@@ -103,23 +101,14 @@
 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; };
+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
 
-template <typename T, typename T2>
-struct hb_is_same : hb_false_t {};
-template <typename T>
-struct hb_is_same<T, T> : hb_true_t {};
+template <typename T, typename T2> struct hb_is_same : hb_false_t {};
+template <typename T>              struct hb_is_same<T, T> : hb_true_t {};
 #define hb_is_same(T, T2) hb_is_same<T, T2>::value
 
-
-/*
- * Meta-functions.
- */
-
 template <typename T> struct hb_is_signed;
 /* https://github.com/harfbuzz/harfbuzz/issues/1535 */
 template <> struct hb_is_signed<int8_t> { enum { value = true }; };
@@ -151,5 +140,14 @@
 template <> struct hb_is_integer<unsigned long long> { enum { value = true }; };
 #define hb_is_integer(T) hb_is_integer<T>::value
 
+/* Function overloading SFINAE and priority. */
+
+#define HB_AUTO_RETURN_EXPR(E) -> decltype ((E)) { return (E); }
+#define HB_VOID_RETURN_EXPR(E) -> hb_void_tt<decltype ((E))> { (E); }
+
+template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
+template <>             struct hb_priority<0> {};
+#define hb_prioritize hb_priority<16> ()
+
 
 #endif /* HB_META_HH */
diff --git a/src/hb.hh b/src/hb.hh
index 172b6ac..ee35c4d 100644
--- a/src/hb.hh
+++ b/src/hb.hh
@@ -651,7 +651,7 @@
 #include "hb-atomic.hh"	// Requires: hb-meta
 #include "hb-null.hh"	// Requires: hb-meta
 #include "hb-algs.hh"	// Requires: hb-meta hb-null
-#include "hb-iter.hh"	// Requires: hb-meta
+#include "hb-iter.hh"	// Requires: hb-algs hb-meta
 #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