/* Enable bitwise ops on enums marked as flags_t */ /* To my surprise, looks like the function resolver is happy to silently cast * one enum to another... So this doesn't provide the type-checking that I * originally had in mind... :(. * * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163
*/ #ifdef _MSC_VER # pragma warning(disable:4200) # pragma warning(disable:4800) #endif #define HB_MARK_AS_FLAG_T(T) \ extern"C++" { \ staticinline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \ staticinline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \ staticinline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ staticinline constexpr unsignedoperator ~ (T r) { return (~(unsigned) r); } \ staticinline T& operator |= (T &l, T r) { l = l | r; return l; } \ staticinline T& operator &= (T& l, T r) { l = l & r; return l; } \ staticinline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
} \
static_assert (true, "")
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; }
private:
hb_reference_wrapper<Appl> a;
V v;
}; template <unsigned Pos=1, typename Appl, typename V> auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
(( hb_partial_t<Pos, Appl, V> (a, v) ))
/* The following, HB_PARTIALIZE, macro uses a particular corner-case * of C++11 that is not particularly well-supported by all compilers. * What's happening is that it's using "this" in a trailing return-type * via decltype(). Broken compilers deduce the type of "this" pointer * in that context differently from what it resolves to in the body * of the function. * * One probable cause of this is that at the time of trailing return * type declaration, "this" points to an incomplete type, whereas in * the function body the type is complete. That doesn't justify the * error in any way, but is probably what's happening. * * In the case of MSVC, we get around this by using C++14 "decltype(auto)" * which deduces the type from the actual return statement. For gcc 4.8 * we use "+this" instead of "this" which produces an rvalue that seems * to be deduced as the same type with this particular compiler, and seem * to be fine as default code path as well.
*/ #ifdef _MSC_VER /* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \ #define HB_PARTIALIZE(Pos) \ template <typename _T> \
decltype(auto) operator () (_T&& _v) const \
{ return hb_partial<Pos> (this, std::forward<_T> (_v)); } \
static_assert (true, "") #else /* https://github.com/harfbuzz/harfbuzz/issues/1724 */ #define HB_PARTIALIZE(Pos) \ template <typename _T> \ autooperator () (_T&& _v) const HB_AUTO_RETURN \
(hb_partial<Pos> (+this, std::forward<_T> (_v))) \
static_assert (true, "") #endif
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, that would silently convert between different-signedness integers. * Instead we accept two different types, such that compiler can err if
* 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> staticinlineunsignedint
hb_popcount (T v)
{ #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) if (sizeof (T) <= sizeof (unsignedint)) return __builtin_popcount (v);
if (sizeof (T) <= sizeof (unsignedlong)) return __builtin_popcountl (v);
if (sizeof (T) <= sizeof (unsignedlonglong)) 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);
}
/* Returns the number of bits needed to store number */ template <typename T> staticinlineunsignedint
hb_bit_storage (T v)
{ if (unlikely (!v)) return 0;
/* Returns the number of zero bits in the least significant side of v */ template <typename T> staticinlineunsignedint
hb_ctz (T v)
{ if (unlikely (!v)) return 8 * sizeof (T);
if (sizeof (T) <= 4)
{ /* "bithacks" */ unsignedint 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" */ unsignedint 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)
{ unsignedint shift = 64; return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
}
/* ASCII tag/character handling */ staticinlinebool ISALPHA (unsignedchar c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } staticinlinebool ISALNUM (unsignedchar c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } staticinlinebool ISSPACE (unsignedchar c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } staticinlineunsignedchar TOUPPER (unsignedchar c)
{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } staticinlineunsignedchar TOLOWER (unsignedchar c)
{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } staticinlinebool ISHEX (unsignedchar c)
{ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } staticinlineunsignedchar TOHEX (uint8_t c)
{ return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; } staticinline uint8_t FROMHEX (unsignedchar c)
{ return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; }
staticinlineunsignedint DIV_CEIL (constunsignedint a, unsignedint b)
{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH template <typename Type, unsignedint n> staticinlineunsignedint ARRAY_LENGTH (const Type (&)[n]) { return n; } /* A const version, but does not detect erratically being called on pointers. */ #define ARRAY_LENGTH_CONST(__array) ((signedint) (sizeof (__array) / sizeof (__array[0])))
staticinlinevoid *
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);
}
staticinlineint
hb_memcmp (constvoid *a, constvoid *b, unsignedint len)
{ /* It's illegal to pass NULL to memcmp(), even if len is zero. * So, wrap it.
* https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ if (unlikely (!len)) return 0; return memcmp (a, b, len);
}
staticinlinevoid *
hb_memset (void *s, int c, unsignedint n)
{ /* It's illegal to pass NULL to memset(), even if n is zero. */ if (unlikely (!n)) return 0; return memset (s, c, n);
}
template <typename T> staticinlinebool
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> staticinlinebool
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> staticinlinebool
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> staticinlinebool
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);
}
/* * Overflow checking.
*/
/* Consider __builtin_mul_overflow use here also */ staticinlinebool
hb_unsigned_mul_overflows (unsignedint count, unsignedint size)
{ return (size > 0) && (count >= ((unsignedint) -1) / size);
}
/* hb_qsort function to be exported. Parameters: base is the array to be sorted nel is the number of elements in the array width is the size in bytes of each element of the array compar is the comparison function arg (optional) is a pointer to be passed to the comparison function
/* swap a and b */ /* a and b must not be equal! */ staticinlinevoid 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> staticinlineint 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); return 1;
} return 0;
}
/* Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr, with the smallest swap so that the blocks are in the opposite order. Blocks may be internally re-ordered e.g. 12345ab -> ab34512 123abc -> abc123 12abcde -> deabc12
*/ staticinlinevoid sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
{ if(na > 0 && nb > 0) { if(na > nb) { sort_r_swap(ptr, ptr+na, nb); } else { sort_r_swap(ptr, ptr+nb, na); }
}
}
/* Implement recursive quicksort ourselves */ /* Note: quicksort is not stable, equivalent values may be swapped */ template <typename ...Ts> staticinlinevoid sort_r_simple(void *base, size_t nel, size_t w, int (*compar)(constvoid *_a, constvoid *_b,
Ts... _ds),
Ts... ds)
{ char *b = (char *)base, *end = b + nel*w;
/* Use median of second, middle and second-last items as pivot. First and last may have been swapped with pivot and therefore be extreme
*/ char *l[3];
l[0] = b + w;
l[1] = b+w*(nel/2);
l[2] = last - w;
/* swap mid value (l[1]), and last element to put pivot as last element */ if(l[1] != last) { sort_r_swap(l[1], last, w); }
/* pl is the next item on the left to be compared to the pivot pr is the last item on the right that was compared to the pivot ple is the left position to put the next item that equals the pivot ple is the last right position where we put an item that equals the pivot v- end (beyond the array) EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE. ^- b ^- ple ^- pl ^- pr ^- pre ^- last (where the pivot is) Pivot comparison key: E = equal, L = less than, u = unknown, G = greater than, E = equal
*/
pivot = last;
ple = pl = b;
pre = pr = last;
/* Strategy: Loop into the list from the left and right at the same time to find: - an item on the left that is greater than the pivot - an item on the right that is less than the pivot Once found, they are swapped and the loop continues. Meanwhile items that are equal to the pivot are moved to the edges of the 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; } elseif(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); }
} elseif(cmp < 0) { if(pl < pr) { sort_r_swap(pl, pr, w); }
pl += w; break;
}
}
}
pl = pr; /* pr may have gone below pl */
/* Now we need to go from: EEELLLGGGGEEEE to: LLLEEEEEEEGGGG Pivot comparison key: E = equal, L = less than, u = unknown, G = greater than, E = equal
*/
sort_r_swap_blocks(b, ple-b, pl-ple);
sort_r_swap_blocks(pr, pre-pr, end-pre);
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 ist noch experimentell.