hb-meta.hh 14.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 * 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"


B
Behdad Esfahbod 已提交
33
/*
34
 * C++ template meta-programming & fundamentals used with them.
B
Behdad Esfahbod 已提交
35 36
 */

B
Behdad Esfahbod 已提交
37 38 39 40 41 42 43 44 45 46 47
/* Void!  For when we need a expression-type of void. */
struct hb_void_t { typedef void value; };

/* Void meta-function ala std::void_t
 * https://en.cppreference.com/w/cpp/types/void_t */
template<typename... Ts> struct _hb_void_tt { typedef void type; };
template<typename... Ts> using hb_void_tt = typename _hb_void_tt<Ts...>::type;

template<typename Head, typename... Ts> struct _hb_head_tt { typedef Head type; };
template<typename... Ts> using hb_head_tt = typename _hb_head_tt<Ts...>::type;

48 49 50 51
template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
using hb_true_type = hb_bool_constant<true>;
using hb_false_type = hb_bool_constant<false>;
B
Behdad Esfahbod 已提交
52 53


54 55 56 57 58 59 60 61
/* Basic type SFINAE. */

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
/* Concepts/Requires alias: */
#define hb_requires(Cond) hb_enable_if((Cond))

62 63
template <typename T, typename T2> struct hb_is_same : hb_false_type {};
template <typename T>              struct hb_is_same<T, T> : hb_true_type {};
64 65
#define hb_is_same(T, T2) hb_is_same<T, T2>::value

66 67
/* Function overloading SFINAE and priority. */

B
Behdad Esfahbod 已提交
68
#define HB_RETURN(Ret, E) -> hb_head_tt<Ret, decltype ((E))> { return (E); }
69 70
#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
#define HB_VOID_RETURN(E) -> hb_void_tt<decltype ((E))> { (E); }
71 72 73 74 75

template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
template <>             struct hb_priority<0> {};
#define hb_prioritize hb_priority<16> ()

B
Behdad Esfahbod 已提交
76
#define HB_FUNCOBJ(x) static_const x HB_UNUSED
B
Behdad Esfahbod 已提交
77

B
Behdad Esfahbod 已提交
78

B
Behdad Esfahbod 已提交
79 80 81
template <typename T> struct hb_match_identity { typedef T type; };
template <typename T> using hb_type_identity = typename hb_match_identity<T>::type;

B
Behdad Esfahbod 已提交
82
struct
83
{
B
Behdad Esfahbod 已提交
84
  template <typename T>
B
Behdad Esfahbod 已提交
85
  T* operator () (T& arg) const
B
Behdad Esfahbod 已提交
86
  {
87 88
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
B
Behdad Esfahbod 已提交
89 90 91 92
    /* https://en.cppreference.com/w/cpp/memory/addressof */
    return reinterpret_cast<T*> (
	     &const_cast<char&> (
		reinterpret_cast<const volatile char&> (arg)));
93
#pragma GCC diagnostic pop
B
Behdad Esfahbod 已提交
94
  }
B
Behdad Esfahbod 已提交
95 96
}
HB_FUNCOBJ (hb_addressof);
97

98
template <typename T> static inline T hb_declval ();
B
Behdad Esfahbod 已提交
99
#define hb_declval(T) (hb_declval<T> ())
B
Behdad Esfahbod 已提交
100

B
Behdad Esfahbod 已提交
101 102
template <typename T> struct hb_match_const		{ typedef T type; static constexpr bool value = false; };
template <typename T> struct hb_match_const<const T>	{ typedef T type; static constexpr bool value = true;  };
103
template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
104
template <typename T> using hb_add_const = const T;
B
Behdad Esfahbod 已提交
105
#define hb_is_const(T) hb_match_const<T>::value
B
Behdad Esfahbod 已提交
106 107 108
template <typename T> struct hb_match_reference		{ typedef T type; static constexpr bool value = false; };
template <typename T> struct hb_match_reference<T &>	{ typedef T type; static constexpr bool value = true;  };
template <typename T> struct hb_match_reference<T &&>	{ typedef T type; static constexpr bool value = true;  };
109
template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
110 111 112 113 114 115
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference<T> (hb_prioritize));
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>;
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
B
Behdad Esfahbod 已提交
116
#define hb_is_reference(T) hb_match_reference<T>::value
B
Behdad Esfahbod 已提交
117 118
template <typename T> struct hb_match_pointer		{ typedef T type; static constexpr bool value = false; };
template <typename T> struct hb_match_pointer<T *>	{ typedef T type; static constexpr bool value = true;  };
119
template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
120 121 122
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
B
Behdad Esfahbod 已提交
123
#define hb_is_pointer(T) hb_match_pointer<T>::value
B
Behdad Esfahbod 已提交
124

125

B
Behdad Esfahbod 已提交
126
/* TODO Add feature-parity to std::decay. */
B
Behdad Esfahbod 已提交
127 128
template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

template<bool B, class T, class F>
struct _hb_conditional { typedef T type; };
template<class T, class F>
struct _hb_conditional<false, T, F> { typedef F type; };
template<bool B, class T, class F>
using hb_conditional = typename _hb_conditional<B, T, F>::type;


template <typename From, typename To>
struct hb_is_convertible
{
  private:
  static constexpr bool   from_void = hb_is_same (void, hb_decay<From>);
  static constexpr bool     to_void = hb_is_same (void, hb_decay<To>  );
  static constexpr bool either_void = from_void || to_void;
  static constexpr bool   both_void = from_void && to_void;

147
  static hb_true_type impl2 (hb_conditional<to_void, int, To>);
148 149

  template <typename T>
B
Minor  
Behdad Esfahbod 已提交
150
  static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
151
  template <typename T>
152
  static hb_false_type impl (hb_priority<0>);
153 154 155 156 157 158 159
  public:
  static constexpr bool value = both_void ||
		       (!either_void &&
			decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
};
#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value

B
Behdad Esfahbod 已提交
160
template <typename Base, typename Derived>
B
Behdad Esfahbod 已提交
161
using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
B
Behdad Esfahbod 已提交
162 163
#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value

164
template <typename From, typename To>
165 166 167 168 169
using hb_is_cr_convertible = hb_bool_constant<
  hb_is_same (hb_decay<From>, hb_decay<To>) &&
  (!hb_is_const (From) || hb_is_const (To)) &&
  (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
>;
170
#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
171

172 173 174
/* std::move and std::forward */

template <typename T>
175
static hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
176 177

template <typename T>
178
static T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
179
template <typename T>
180
static T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
181

182 183 184
struct
{
  template <typename T> auto
185
  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
186 187

  template <typename T> auto
188
  operator () (T *v) const HB_AUTO_RETURN (*v)
B
Behdad Esfahbod 已提交
189 190
}
HB_FUNCOBJ (hb_deref);
191

B
Behdad Esfahbod 已提交
192 193 194 195 196 197 198
struct
{
  template <typename T> auto
  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))

  template <typename T> auto
  operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
B
Behdad Esfahbod 已提交
199 200
}
HB_FUNCOBJ (hb_ref);
B
Behdad Esfahbod 已提交
201

202 203 204 205 206 207
template <typename T>
struct hb_reference_wrapper
{
  hb_reference_wrapper (T v) : v (v) {}
  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
B
Behdad Esfahbod 已提交
208
  operator T () const { return v; }
209 210 211 212 213 214
  T get () const { return v; }
  T v;
};
template <typename T>
struct hb_reference_wrapper<T&>
{
B
Behdad Esfahbod 已提交
215
  hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
216 217
  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
B
Behdad Esfahbod 已提交
218 219
  operator T& () const { return *v; }
  T& get () const { return *v; }
220 221 222
  T* v;
};

223

B
Behdad Esfahbod 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
template <typename T> struct hb_is_integral		{ static constexpr bool value = false;};
template <> struct hb_is_integral<char> 		{ static constexpr bool value = true; };
template <> struct hb_is_integral<signed char> 		{ static constexpr bool value = true; };
template <> struct hb_is_integral<unsigned char> 	{ static constexpr bool value = true; };
template <> struct hb_is_integral<signed short> 	{ static constexpr bool value = true; };
template <> struct hb_is_integral<unsigned short> 	{ static constexpr bool value = true; };
template <> struct hb_is_integral<signed int> 		{ static constexpr bool value = true; };
template <> struct hb_is_integral<unsigned int> 	{ static constexpr bool value = true; };
template <> struct hb_is_integral<signed long> 		{ static constexpr bool value = true; };
template <> struct hb_is_integral<unsigned long> 	{ static constexpr bool value = true; };
template <> struct hb_is_integral<signed long long> 	{ static constexpr bool value = true; };
template <> struct hb_is_integral<unsigned long long> 	{ static constexpr bool value = true; };

template <typename T> struct hb_is_floating_point	{ static constexpr bool value = false;};
template <> struct hb_is_floating_point<float> 		{ static constexpr bool value = true; };
template <> struct hb_is_floating_point<double> 	{ static constexpr bool value = true; };
template <> struct hb_is_floating_point<long double> 	{ static constexpr bool value = true; };

#define hb_is_integral(T) hb_is_integral<T>::value
B
Behdad Esfahbod 已提交
243
template <typename T> struct hb_is_signed;
B
Behdad Esfahbod 已提交
244 245 246 247 248 249 250 251 252 253 254
template <> struct hb_is_signed<char>			{ static constexpr bool value = CHAR_MIN < 0;	};
template <> struct hb_is_signed<signed char>		{ static constexpr bool value = true;		};
template <> struct hb_is_signed<unsigned char>		{ static constexpr bool value = false;		};
template <> struct hb_is_signed<signed short>		{ static constexpr bool value = true;		};
template <> struct hb_is_signed<unsigned short>		{ static constexpr bool value = false;		};
template <> struct hb_is_signed<signed int>		{ static constexpr bool value = true;		};
template <> struct hb_is_signed<unsigned int>		{ static constexpr bool value = false;		};
template <> struct hb_is_signed<signed long>		{ static constexpr bool value = true;		};
template <> struct hb_is_signed<unsigned long>		{ static constexpr bool value = false;		};
template <> struct hb_is_signed<signed long long>	{ static constexpr bool value = true;		};
template <> struct hb_is_signed<unsigned long long>	{ static constexpr bool value = false;		};
255 256 257
template <> struct hb_is_signed<float>			{ static constexpr bool value = true;		};
template <> struct hb_is_signed<double>			{ static constexpr bool value = true;		};
template <> struct hb_is_signed<long double>		{ static constexpr bool value = true;		};
B
Behdad Esfahbod 已提交
258 259
#define hb_is_signed(T) hb_is_signed<T>::value

B
Behdad Esfahbod 已提交
260 261 262 263 264 265 266 267 268 269 270 271
template <typename T> struct hb_int_min;
template <> struct hb_int_min<char>			{ static constexpr char			value = CHAR_MIN;	};
template <> struct hb_int_min<signed char>		{ static constexpr signed char		value = SCHAR_MIN;	};
template <> struct hb_int_min<unsigned char>		{ static constexpr unsigned char	value = 0;		};
template <> struct hb_int_min<signed short>		{ static constexpr signed short		value = SHRT_MIN;	};
template <> struct hb_int_min<unsigned short>		{ static constexpr unsigned short	value = 0;		};
template <> struct hb_int_min<signed int>		{ static constexpr signed int		value = INT_MIN;	};
template <> struct hb_int_min<unsigned int>		{ static constexpr unsigned int		value = 0;		};
template <> struct hb_int_min<signed long>		{ static constexpr signed long		value = LONG_MIN;	};
template <> struct hb_int_min<unsigned long>		{ static constexpr unsigned long	value = 0;		};
template <> struct hb_int_min<signed long long>		{ static constexpr signed long long	value = LLONG_MIN;	};
template <> struct hb_int_min<unsigned long long>	{ static constexpr unsigned long long	value = 0;		};
B
Behdad Esfahbod 已提交
272
#define hb_int_min(T) hb_int_min<T>::value
B
Behdad Esfahbod 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285
template <typename T> struct hb_int_max;
template <> struct hb_int_max<char>			{ static constexpr char			value = CHAR_MAX;	};
template <> struct hb_int_max<signed char>		{ static constexpr signed char		value = SCHAR_MAX;	};
template <> struct hb_int_max<unsigned char>		{ static constexpr unsigned char	value = UCHAR_MAX;	};
template <> struct hb_int_max<signed short>		{ static constexpr signed short		value = SHRT_MAX;	};
template <> struct hb_int_max<unsigned short>		{ static constexpr unsigned short	value = USHRT_MAX;	};
template <> struct hb_int_max<signed int>		{ static constexpr signed int		value = INT_MAX;	};
template <> struct hb_int_max<unsigned int>		{ static constexpr unsigned int		value = UINT_MAX;	};
template <> struct hb_int_max<signed long>		{ static constexpr signed long		value = LONG_MAX;	};
template <> struct hb_int_max<unsigned long>		{ static constexpr unsigned long	value = ULONG_MAX;	};
template <> struct hb_int_max<signed long long>		{ static constexpr signed long long	value = LLONG_MAX;	};
template <> struct hb_int_max<unsigned long long>	{ static constexpr unsigned long long	value = ULLONG_MAX;	};
#define hb_int_max(T) hb_int_max<T>::value
B
Behdad Esfahbod 已提交
286

B
Behdad Esfahbod 已提交
287 288 289 290 291 292
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


293
#endif /* HB_META_HH */