struct
{ /* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */ template <typename T> constexpr auto operator () (T&& v) const HB_AUTO_RETURN ( std::forward<T> (v) )
}
HB_FUNCOBJ (hb_identity); struct
{ /* Like identity(), but only retains lvalue-references. Rvalues are returned as rvalues. */ template <typename T> constexpr T& operator () (T& v) const { return v; }
template <typename U1 = T1, typename U2 = T2,
hb_enable_if (std::is_default_constructible<U1>::value &&
std::is_default_constructible<U2>::value)>
hb_pair_t () : first (), second () {}
hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
/* Note. In min/max impl, we can use hb_type_identity<T> for second argument. *However,thatwouldsilentlyconvertbetweendifferent-signednessintegers. *Insteadweaccepttwodifferenttypes,suchthatcompilercanerrif
* comparing integers of different signedness. */ struct
{ template <typename T, typename T2> constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN
(a <= b ? std::forward<T> (a) : std::forward<T2> (b))
}
HB_FUNCOBJ (hb_min); struct
{ template <typename T, typename T2> constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN
(a >= b ? std::forward<T> (a) : std::forward<T2> (b))
}
HB_FUNCOBJ (hb_max); struct
{ template <typename T, typename T2, typename T3> constexpr auto operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN
(hb_min (hb_max (std::forward<T> (x), std::forward<T2> (min)), std::forward<T3> (max)))
}
HB_FUNCOBJ (hb_clamp);
struct
{ template <typename T> void operator () (T& a, T& b) const
{ using std::swap; // allow ADL
swap (a, b);
}
}
HB_FUNCOBJ (hb_swap);
/* *Bithacks.
*/
/* Return the number of 1 bits in v. */ template <typename T> static inline unsigned int
hb_popcount (T v)
{ #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int)) return __builtin_popcount (v);
if (sizeof (T) <= sizeof (unsigned long)) return __builtin_popcountl (v);
if (sizeof (T) <= sizeof (unsigned long long)) return __builtin_popcountll (v); #endif
if (sizeof (T) <= 4)
{ /* "HACKMEM 169" */
uint32_t y;
y = (v >> 1) &033333333333;
y = v - y - ((y >>1) & 033333333333); return (((y + (y >> 3)) & 030707070707) % 077);
}
if (sizeof (T) == 8)
{ unsigned int shift = 32; return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
}
if (sizeof (T) == 16)
{ unsigned int shift = 64; return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
}
assert (0); return0; /* Shut up stupid compiler. */
}
/* Returns the number of bits needed to store number */ template <typename T> static inline unsigned int
hb_bit_storage (T v)
{
if (unlikely (!v)) return0;
if (sizeof (T) <= 4)
{ /* "bithacks" */ constunsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; constunsigned int S[] = {1, 2, 4, 8, 16}; unsigned int r = 0;
for (int i = 4; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
} return r + 1;
}
if (sizeof (T) <= 8)
{ /* "bithacks" */ const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL}; constunsigned int S[] = {1, 2, 4, 8, 16, 32}; unsigned int r = 0;
for (int i = 5; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
} return r + 1;
}
if (sizeof (T) == 16)
{ unsigned int shift = 64; return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
hb_bit_storage<uint64_t> ((uint64_t) v);
}
assert (0); return0; /* Shut up stupid compiler. */
}
/* Returns the number of zero bits in the least significant side of v */ template <typename T> static inline unsigned int
hb_ctz (T v)
{
if (unlikely (!v)) return8 * sizeof (T);
if (sizeof (T) <= sizeof (unsigned long)) return __builtin_ctzl (v);
if (sizeof (T) <= sizeof (unsigned long long)) return __builtin_ctzll (v); #endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
if (sizeof (T) <= sizeof (unsigned int))
{ unsigned long where;
_BitScanForward (&where, v); return where;
} # if defined(_WIN64)
if (sizeof (T) <= 8)
{ unsigned long where;
_BitScanForward64 (&where, v); return where;
} # endif #endif
if (sizeof (T) <= 4)
{ /* "bithacks" */ unsigned int c = 32;
v &= - (int32_t) v;
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1; return c;
}
if (sizeof (T) <= 8)
{ /* "bithacks" */ unsigned int c = 64;
v &= - (int64_t) (v);
if (v) c--;
if (v & 0x00000000FFFFFFFFULL) c -= 32;
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
if (v & 0x3333333333333333ULL) c -= 2;
if (v & 0x5555555555555555ULL) c -= 1; return c;
}
if (sizeof (T) == 16)
{ unsigned int shift = 64; return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
}
assert (0); return0; /* Shut up stupid compiler. */
}
/* *Tinystuff.
*/
/* ASCII tag/character handling */ static inline bool ISALPHA (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } static inline bool ISALNUM (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } static inline unsigned char TOUPPER (unsigned char c)
{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } static inline unsigned char TOLOWER (unsigned char c)
{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } static inline bool ISHEX (unsigned char c)
{ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } static inline unsigned char TOHEX (uint8_t c)
{ return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; } static inline uint8_t FROMHEX (unsigned char c)
{ return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; }
static inline unsigned int DIV_CEIL (constunsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH template <typename Type, unsigned int n> static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } /* A const version, but does not detect erratically being called on pointers. */ #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
static inline void *
hb_memcpy (void *__restrict dst, constvoid *__restrict src, size_t len)
{ /* It's illegal to pass 0 as size to memcpy. */
if (unlikely (!len)) return dst; return memcpy (dst, src, len);
}
static inline int
hb_memcmp (constvoid *a, constvoid *b, unsigned int len)
{ /* It's illegal to pass NULL to memcmp(), even if len is zero. *So,wrapit.
* https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
if (unlikely (!len)) return0; return memcmp (a, b, len);
}
static inline void *
hb_memset (void *s, int c, unsigned int n)
{ /* It's illegal to pass NULL to memset(), even if n is zero. */
if (unlikely (!n)) return0; return memset (s, c, n);
}
static inline unsigned int
hb_ceil_to_4 (unsigned int v)
{ return ((v - 1) | 3) + 1;
}
template <typename T> static inline bool
hb_in_range (T u, T lo, T hi)
{
static_assert (!std::is_signed<T>::value, "");
/* The casts below are important as if T is smaller than int,
* the subtract results will become a signed int! */ return (T)(u - lo) <= (T)(hi - lo);
} template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
{ return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
} template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
{ return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
} template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4)
{ return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4);
}
/* *Overflowchecking.
*/
/* Consider __builtin_mul_overflow use here also */ static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
{ return (size > 0) && (count >= ((unsigned int) -1) / size);
}
/* swap a and b */ /* a and b must not be equal! */ static inline void sort_r_swap(char *__restrict a, char *__restrict b,
size_t w)
{
char tmp, *end = a+w;
for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
}
/* swap a, b iff a>b */ /* a and b must not be equal! */ /* __restrict is same as restrict but better support on old machines */ template <typename ...Ts> static inline int sort_r_cmpswap(char *__restrict a,
char *__restrict b, size_t w,
int (*compar)(constvoid *_a, constvoid *_b,
Ts... _ds),
Ts... ds)
{
if(compar(a, b, ds...) > 0) {
sort_r_swap(a, b, w); return1;
} return0;
}
/* Strategy: Loopintothelistfromtheleftandrightatthesametimetofind: -anitemontheleftthatisgreaterthanthepivot -anitemontherightthatislessthanthepivot Oncefound,theyareswappedandtheloopcontinues. Meanwhileitemsthatareequaltothepivotaremovedtotheedgesofthe array.
*/ while(pl < pr) { /* Move left hand items which are equal to the pivot to the far left.
break when we find an item that is greater than the pivot */
for(; pl < pr; pl += w) {
cmp = compar(pl, pivot, ds...);
if(cmp > 0) { break; } else if(cmp == 0) {
if(ple < pl) { sort_r_swap(ple, pl, w); }
ple += w;
}
} /* break if last batch of left hand items were equal to pivot */
if(pl >= pr) { break; } /* Move right hand items which are equal to the pivot to the far right.
break when we find an item that is less than the pivot */
for(; pl < pr; ) {
pr -= w; /* Move right pointer onto an unprocessed item */
cmp = compar(pr, pivot, ds...);
if(cmp == 0) {
pre -= w;
if(pr < pre) { sort_r_swap(pr, pre, w); }
} else if(cmp < 0) {
if(pl < pr) { sort_r_swap(pl, pr, w); }
pl += w; break;
}
}
}
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++)
{ unsigned int j = i; while (j && compar (&array[j - 1], &array[i]) > 0)
j--;
if (i == j) continue; /* Move item i to occupy place for item j, shift what's in between. */
{
T t = array[i];
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
array[j] = t;
}
if (array2)
{
T3 t = array2[i];
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
array2[j] = t;
}
}
}
template <typename T> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
{
hb_stable_sort (array, len, compar, (int *) nullptr);
}
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{ unsigned int v; const char *p = s; const char *end = p + len;
if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base))) return false;
*out = v; returntrue;
}
/* Operators. */
struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
}
HB_FUNCOBJ (hb_bitwise_and); struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
}
HB_FUNCOBJ (hb_bitwise_or); struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
}
HB_FUNCOBJ (hb_bitwise_xor); struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b)
}
HB_FUNCOBJ (hb_bitwise_lt); struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
}
HB_FUNCOBJ (hb_bitwise_gt); // aka sub struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b)
}
HB_FUNCOBJ (hb_bitwise_le); struct
{ HB_PARTIALIZE(2); template <typename T> constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b)
}
HB_FUNCOBJ (hb_bitwise_ge); struct
{ template <typename T> constexpr auto operator () (const T &a) const HB_AUTO_RETURN (~a)
}
HB_FUNCOBJ (hb_bitwise_neg);
struct
{ HB_PARTIALIZE(2); template <typename T, typename T2> constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b)
}
HB_FUNCOBJ (hb_add); struct
{ HB_PARTIALIZE(2); template <typename T, typename T2> constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b)
}
HB_FUNCOBJ (hb_sub); struct
{ HB_PARTIALIZE(2); template <typename T, typename T2> constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a)
}
HB_FUNCOBJ (hb_rsub); struct
{ HB_PARTIALIZE(2); template <typename T, typename T2> constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
}
HB_FUNCOBJ (hb_mul); struct
{ HB_PARTIALIZE(2); template <typename T, typename T2> constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b)
}
HB_FUNCOBJ (hb_div); struct
{ HB_PARTIALIZE(2); template <typename T, typename T2> constexpr auto operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
}
HB_FUNCOBJ (hb_mod); struct
{ template <typename T> constexpr auto operator () (const T &a) const HB_AUTO_RETURN (+a)
}
HB_FUNCOBJ (hb_pos); struct
{ template <typename T> constexpr auto operator () (const T &a) const HB_AUTO_RETURN (-a)
}
HB_FUNCOBJ (hb_neg); struct
{ template <typename T> constexpr auto operator () (T &a) const HB_AUTO_RETURN (++a)
}
HB_FUNCOBJ (hb_inc); struct
{ template <typename T> constexpr auto operator () (T &a) const HB_AUTO_RETURN (--a)
}
HB_FUNCOBJ (hb_dec);
/* Compiler-assisted vectorization. */
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
* basically a fixed-size bitset. */ template <typename elt_t, unsigned int byte_size> struct hb_vector_size_t
{
elt_t& operator [] (unsigned int i) { return v[i]; } const elt_t& operator [] (unsigned int i) const { return v[i]; }
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.