Merge pull request #2874 from harfbuzz/constexpr2

Some more cleanup towards using constexpr to simplify our internal datastrcutures.

https://github.com/harfbuzz/harfbuzz/pull/2874
This commit is contained in:
Behdad Esfahbod 2021-02-22 17:40:22 -07:00 committed by GitHub
commit 021a1725ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 186 additions and 442 deletions

View File

@ -54,14 +54,13 @@ jobs:
executor: autotools-executor
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfontconfig1-dev libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip cmake
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfontconfig1-dev libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip
- run: pip3 install fonttools meson --upgrade
- run: ./autogen.sh
- run: make -j32
- run: make distcheck
- run: rm harfbuzz-* && make distdir
- run: cd harfbuzz-* && meson build && ninja -Cbuild test
- run: cd harfbuzz-* && cmake -Bcmakebuild -H. && cmake --build cmakebuild
- run: make dist
- persist_to_workspace:
root: .

View File

@ -19,12 +19,12 @@ jobs:
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
# ideally we should've used meson and ninja here but it complains about coverage or something
- run: cov-analysis-linux64/bin/cov-build --dir cov-int clang src/hb-*.cc -DHAVE_FREETYPE -DHAVE_GRAPHITE2 -DHAVE_GLIB -DHAVE_ICU `pkg-config --cflags freetype2 graphite2 glib-2.0 icu-uc` -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHAVE_ROUNDF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H -DHAVE_GETPAGESIZE -DHB_EXPERIMENTAL_API -c
- run: cov-analysis-linux64/bin/cov-build --dir cov-int clang src/hb-*.cc -DHAVE_FREETYPE -DHAVE_GRAPHITE2 -DHAVE_GLIB -DHAVE_ICU `pkg-config --cflags freetype2 graphite2 glib-2.0 icu-uc` -DHAVE_ROUNDF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H -DHAVE_GETPAGESIZE -DHB_EXPERIMENTAL_API -c
- run: tar czvf harfbuzz.tgz cov-int
- name: submit to coverity
run: |
curl \

View File

@ -102,6 +102,8 @@ if (${HAVE_STDBOOL_H})
add_definitions(-DHAVE_STDBOOL_H)
endif ()
# https://github.com/harfbuzz/harfbuzz/pull/2874#issuecomment-782859099
if (NOT WIN32) add_definitions("-DHAVE_PTHREAD") endif ()
if (MSVC)
add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
@ -406,37 +408,6 @@ if (HB_HAVE_GOBJECT)
)
endif ()
## Atomic ops availability detection
file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
" void memory_barrier (void) { __sync_synchronize (); }
int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
void mutex_unlock (int *m) { __sync_lock_release (m); }
int main () { return 0; }
")
try_compile(HB_HAVE_INTEL_ATOMIC_PRIMITIVES
${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives
${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c)
if (HB_HAVE_INTEL_ATOMIC_PRIMITIVES)
add_definitions(-DHAVE_INTEL_ATOMIC_PRIMITIVES)
endif ()
file(WRITE "${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c"
" #include <atomic.h>
/* This requires Solaris Studio 12.2 or newer: */
#include <mbarrier.h>
void memory_barrier (void) { __machine_rw_barrier (); }
int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
int main () { return 0; }
")
try_compile(HB_HAVE_SOLARIS_ATOMIC_OPS
${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops
${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c)
if (HB_HAVE_SOLARIS_ATOMIC_OPS)
add_definitions(-DHAVE_SOLARIS_ATOMIC_OPS)
endif ()
## Define harfbuzz library
add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})

View File

@ -40,8 +40,6 @@ EXTRA_DIST = \
perf/texts/en-words.txt \
perf/texts/fa-monologue.txt \
perf/texts/fa-thelittleprince.txt \
meson-cc-tests/intel-atomic-primitives-test.c \
meson-cc-tests/solaris-atomic-operations.c \
mingw-configure.sh \
$(NULL)

View File

@ -417,45 +417,6 @@ AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext)
dnl ===========================================================================
AC_CACHE_CHECK([for Intel atomic primitives], hb_cv_have_intel_atomic_primitives, [
hb_cv_have_intel_atomic_primitives=false
AC_TRY_LINK([
void memory_barrier (void) { __sync_synchronize (); }
int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
void mutex_unlock (int *m) { __sync_lock_release (m); }
], [], hb_cv_have_intel_atomic_primitives=true
)
])
if $hb_cv_have_intel_atomic_primitives; then
AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1, [Have Intel __sync_* atomic primitives])
fi
dnl ===========================================================================
AC_CACHE_CHECK([for Solaris atomic operations], hb_cv_have_solaris_atomic_ops, [
hb_cv_have_solaris_atomic_ops=false
AC_TRY_LINK([
#include <atomic.h>
/* This requires Solaris Studio 12.2 or newer: */
#include <mbarrier.h>
void memory_barrier (void) { __machine_rw_barrier (); }
int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
], [], hb_cv_have_solaris_atomic_ops=true
)
])
if $hb_cv_have_solaris_atomic_ops; then
AC_DEFINE(HAVE_SOLARIS_ATOMIC_OPS, 1, [Have Solaris __machine_*_barrier and atomic_* operations])
fi
if test "$os_win32" = no && ! $have_pthread; then
AC_CHECK_HEADERS(sched.h)
AC_SEARCH_LIBS(sched_yield,rt,AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield]))
fi
dnl ===========================================================================
AC_CONFIG_FILES([
Makefile
src/Makefile

View File

@ -1,6 +0,0 @@
void memory_barrier (void) { __sync_synchronize (); }
int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
void mutex_unlock (int *m) { __sync_lock_release (m); }
int main(void) { return 0;}

View File

@ -1,8 +0,0 @@
#include <atomic.h>
/* This requires Solaris Studio 12.2 or newer: */
#include <mbarrier.h>
void memory_barrier (void) { __machine_rw_barrier (); }
int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
int main(void) { return 0; }

View File

@ -285,9 +285,6 @@ if host_machine.system() != 'windows'
if thread_dep.found()
conf.set('HAVE_PTHREAD', 1)
else
check_headers += ['sched.h']
check_funcs += ['sched_yield', {'link_with': 'rt'}]
endif
endif
@ -337,14 +334,6 @@ foreach check : check_funcs
endif
endforeach
if cpp.links(files('meson-cc-tests/intel-atomic-primitives-test.c'), name: 'Intel atomics')
conf.set('HAVE_INTEL_ATOMIC_PRIMITIVES', 1)
endif
if cpp.links(files('meson-cc-tests/solaris-atomic-operations.c'), name: 'Solaris atomic ops')
conf.set('HAVE_SOLARIS_ATOMIC_OPS', 1)
endif
subdir('src')
subdir('util')

View File

@ -35,6 +35,129 @@
#include "hb-number.hh"
/*
* Flags
*/
/* 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++" { \
static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \
static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
} \
static_assert (true, "")
/* Useful for set-operations on small enums.
* For example, for testing "x ∈ {x1, x2, x3}" use:
* (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
*/
#define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
#define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x))
#define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
/*
* Big-endian integers.
*/
/* Endian swap, used in Windows related backends */
static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
{ return (v >> 8) | (v << 8); }
static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
template <typename Type, int Bytes = sizeof (Type)> struct BEInt;
template <typename Type>
struct BEInt<Type, 1>
{
public:
BEInt () = default;
constexpr BEInt (Type V) : v {uint8_t (V)} {}
constexpr operator Type () const { return v; }
private: uint8_t v;
};
template <typename Type>
struct BEInt<Type, 2>
{
public:
BEInt () = default;
constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF),
uint8_t ((V ) & 0xFF)} {}
struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
constexpr operator Type () const
{
#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
defined(__BYTE_ORDER) && \
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
/* Spoon-feed the compiler a big-endian integer with alignment 1.
* https://github.com/harfbuzz/harfbuzz/pull/1398 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
return __builtin_bswap16 (((packed_uint16_t *) this)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
return ((packed_uint16_t *) this)->v;
#endif
#else
return (v[0] << 8)
+ (v[1] );
#endif
}
private: uint8_t v[2];
};
template <typename Type>
struct BEInt<Type, 3>
{
public:
BEInt () = default;
constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF),
uint8_t ((V >> 8) & 0xFF),
uint8_t ((V ) & 0xFF)} {}
constexpr operator Type () const { return (v[0] << 16)
+ (v[1] << 8)
+ (v[2] ); }
private: uint8_t v[3];
};
template <typename Type>
struct BEInt<Type, 4>
{
public:
BEInt () = default;
constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
uint8_t ((V >> 16) & 0xFF),
uint8_t ((V >> 8) & 0xFF),
uint8_t ((V ) & 0xFF)} {}
constexpr operator Type () const { return (v[0] << 24)
+ (v[1] << 16)
+ (v[2] << 8)
+ (v[3] ); }
private: uint8_t v[4];
};
/* Floats. */
/* We want our rounding towards +infinity. */
static inline float
_hb_roundf (float x) { return floorf (x + .5f); }
#define roundf(x) _hb_roundf(x)
/* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits,
* values will be truncated / overlap, and might not decode exactly. */
#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
@ -48,6 +171,7 @@
#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
struct
{
/* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
@ -413,7 +537,7 @@ HB_FUNCOBJ (hb_clamp);
/* Return the number of 1 bits in v. */
template <typename T>
static inline HB_CONST_FUNC unsigned int
static inline unsigned int
hb_popcount (T v)
{
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
@ -454,7 +578,7 @@ hb_popcount (T v)
/* Returns the number of bits needed to store number */
template <typename T>
static inline HB_CONST_FUNC unsigned int
static inline unsigned int
hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
@ -528,7 +652,7 @@ hb_bit_storage (T v)
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
static inline HB_CONST_FUNC unsigned int
static inline unsigned int
hb_ctz (T v)
{
if (unlikely (!v)) return 8 * sizeof (T);

View File

@ -52,7 +52,7 @@
#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
/* C++11-style GCC primitives. */
/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
#define _hb_memory_barrier() __sync_synchronize ()
@ -73,7 +73,8 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
}
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
#elif !defined(HB_NO_MT)
/* C++11 atomics. */
@ -101,117 +102,6 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#elif !defined(HB_NO_MT) && defined(_WIN32)
#include <windows.h>
static inline void _hb_memory_barrier ()
{
#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
/* MinGW has a convoluted history of supporting MemoryBarrier. */
LONG dummy = 0;
InterlockedExchange (&dummy, 1);
#else
MemoryBarrier ();
#endif
}
#define _hb_memory_barrier() _hb_memory_barrier ()
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
static_assert ((sizeof (LONG) == sizeof (int)), "");
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#define _hb_memory_barrier() __sync_synchronize ()
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
#include <atomic.h>
#include <mbarrier.h>
#define _hb_memory_r_barrier() __machine_r_barrier ()
#define _hb_memory_w_barrier() __machine_w_barrier ()
#define _hb_memory_barrier() __machine_rw_barrier ()
static inline int _hb_fetch_and_add (int *AI, int V)
{
_hb_memory_w_barrier ();
int result = atomic_add_int_nv ((uint_t *) AI, V) - V;
_hb_memory_r_barrier ();
return result;
}
static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
{
_hb_memory_w_barrier ();
bool result = atomic_cas_ptr (P, O, N) == O;
_hb_memory_r_barrier ();
return result;
}
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
#include <libkern/OSAtomic.h>
#ifdef __MAC_OS_X_MIN_REQUIRED
#include <AvailabilityMacros.h>
#elif defined(__IPHONE_OS_MIN_REQUIRED)
#include <Availability.h>
#endif
#define _hb_memory_barrier() OSMemoryBarrier ()
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
#endif
#endif
#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
#include <builtins.h>
#define _hb_memory_barrier() __lwsync ()
static inline int _hb_fetch_and_add (int *AI, int V)
{
_hb_memory_barrier ();
int result = __fetch_and_add (AI, V);
_hb_memory_barrier ();
return result;
}
static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
{
_hb_memory_barrier ();
bool result = __compare_and_swaplp (P, &O, N);
_hb_memory_barrier ();
return result;
}
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N))
static_assert ((sizeof (long) == sizeof (void *)), "");
#elif defined(HB_NO_MT)
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
@ -259,9 +149,11 @@ inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory
#endif
#define HB_ATOMIC_INT_INIT(V) {V}
struct hb_atomic_int_t
{
hb_atomic_int_t () = default;
constexpr hb_atomic_int_t (int v) : v (v) {}
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
@ -269,16 +161,17 @@ struct hb_atomic_int_t
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
int v;
int v = 0;
};
#define HB_ATOMIC_PTR_INIT(V) {V}
template <typename P>
struct hb_atomic_ptr_t
{
typedef hb_remove_pointer<P> T;
hb_atomic_ptr_t () = default;
constexpr hb_atomic_ptr_t (T* v) : v (v) {}
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
@ -288,7 +181,7 @@ struct hb_atomic_ptr_t
T * operator -> () const { return get (); }
template <typename C> operator C * () const { return get (); }
T *v;
T *v = nullptr;
};

View File

@ -89,8 +89,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
nullptr, /* destroy */
0, /* index */
HB_ATOMIC_INT_INIT (1000), /* upem */
HB_ATOMIC_INT_INIT (0), /* num_glyphs */
1000, /* upem */
0, /* num_glyphs */
/* Zero for the rest is fine. */
};

View File

@ -81,7 +81,7 @@ struct hb_face_t
return blob;
}
HB_PURE_FUNC unsigned int get_upem () const
unsigned int get_upem () const
{
unsigned int ret = upem.get_relaxed ();
if (unlikely (!ret))

View File

@ -80,6 +80,11 @@ static inline Type& StructAfter(TObject &X)
* Size checking
*/
/* Size signifying variable-sized array */
#ifndef HB_VAR_ARRAY
#define HB_VAR_ARRAY 1
#endif
/* Check _assertion in a method environment */
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
void _instance_assertion_on_line_##_line () const \

View File

@ -49,6 +49,10 @@ 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>;
/* Static-assert as expression. */
template <bool cond> struct static_assert_expr;
template <> struct static_assert_expr<true> : hb_false_type {};
#define static_assert_expr(C) static_assert_expr<C>::value
/* Basic type SFINAE. */
@ -220,6 +224,8 @@ struct hb_reference_wrapper<T&>
};
/* Type traits */
template <typename T>
using hb_is_integral = hb_bool_constant<
hb_is_same (hb_decay<T>, char) ||
@ -292,6 +298,15 @@ template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigne
#define hb_int_max(T) hb_int_max<T>::value
/* Class traits. */
#define HB_DELETE_COPY_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
TypeName() = delete; \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
template <typename T, typename>
struct _hb_is_destructible : hb_false_type {};

View File

@ -73,24 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
# include <sched.h>
# define HB_SCHED_YIELD() sched_yield ()
#else
# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
#endif
/* This actually is not a totally awful implementation. */
typedef volatile int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) *(M) = 0
#define hb_mutex_impl_lock(M) HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
#define hb_mutex_impl_unlock(M) __sync_lock_release (M)
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
#elif defined(HB_NO_MT)
typedef int hb_mutex_impl_t;

View File

@ -140,9 +140,7 @@ struct hb_lockable_set_t
* Reference-count.
*/
#define HB_REFERENCE_COUNT_INERT_VALUE 0
#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)}
#define HB_REFERENCE_COUNT_INIT {0}
struct hb_reference_count_t
{
@ -152,9 +150,9 @@ struct hb_reference_count_t
int get_relaxed () const { return ref_count.get_relaxed (); }
int inc () const { return ref_count.inc (); }
int dec () const { return ref_count.dec (); }
void fini () { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); }
void fini () { ref_count.set_relaxed (-0x0000DEAD); }
bool is_inert () const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; }
bool is_inert () const { return !ref_count.get_relaxed (); }
bool is_valid () const { return ref_count.get_relaxed () > 0; }
};
@ -197,15 +195,10 @@ struct hb_user_data_array_t
struct hb_object_header_t
{
hb_reference_count_t ref_count;
mutable hb_atomic_int_t writable;
mutable hb_atomic_int_t writable = 0;
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
};
#define HB_OBJECT_HEADER_STATIC \
{ \
HB_REFERENCE_COUNT_INIT, \
HB_ATOMIC_INT_INIT (false), \
HB_ATOMIC_PTR_INIT (nullptr) \
}
#define HB_OBJECT_HEADER_STATIC {}
/*

View File

@ -53,7 +53,7 @@ namespace OT {
*/
/* Integer types in big-endian order and no alignment requirement */
template <typename Type, unsigned int Size>
template <typename Type, unsigned int Size = sizeof (Type)>
struct IntType
{
typedef Type type;
@ -107,12 +107,12 @@ struct IntType
DEFINE_SIZE_STATIC (Size);
};
typedef IntType<uint8_t, 1> HBUINT8; /* 8-bit unsigned integer. */
typedef IntType<int8_t, 1> HBINT8; /* 8-bit signed integer. */
typedef IntType<uint16_t, 2> HBUINT16; /* 16-bit unsigned integer. */
typedef IntType<int16_t, 2> HBINT16; /* 16-bit signed integer. */
typedef IntType<uint32_t, 4> HBUINT32; /* 32-bit unsigned integer. */
typedef IntType<int32_t, 4> HBINT32; /* 32-bit signed integer. */
typedef IntType<uint8_t> HBUINT8; /* 8-bit unsigned integer. */
typedef IntType<int8_t> HBINT8; /* 8-bit signed integer. */
typedef IntType<uint16_t> HBUINT16; /* 16-bit unsigned integer. */
typedef IntType<int16_t> HBINT16; /* 16-bit signed integer. */
typedef IntType<uint32_t> HBUINT32; /* 32-bit unsigned integer. */
typedef IntType<int32_t> HBINT32; /* 32-bit signed integer. */
/* Note: we cannot defined a signed HBINT24 because there's no corresponding C type.
* Works for unsigned, but not signed, since we rely on compiler for sign-extension. */
typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */

View File

@ -142,7 +142,7 @@
OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
/* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
/* static_assert_expr (len(FromGlyphs) == len(ToGlyphs)) */
#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
OT_SUBLOOKUP(Name, 1, \
@ -151,7 +151,7 @@
OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
/* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
/* static_assert_expr (len(FirstGlyphs) == len(LigatureSetOffsets)) */
#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))

View File

@ -175,7 +175,7 @@ enum indic_matra_category_t {
#define INDIC_COMBINE_CATEGORIES(S,M) \
( \
ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
static_assert_expr (S < 255 && M < 255) + \
( S | \
( \
( \

View File

@ -265,8 +265,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_myanmar;
/* https://github.com/harfbuzz/harfbuzz/issues/1162 */
#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
case HB_SCRIPT_MYANMAR_ZAWGYI:
/* https://github.com/harfbuzz/harfbuzz/issues/1162 */
return &_hb_ot_complex_shaper_myanmar_zawgyi;

View File

@ -524,7 +524,7 @@ struct hb_serialize_context_t
template <typename T>
void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
{
auto &off = * ((BEInt<T, sizeof (T)> *) (parent->head + link.position));
auto &off = * ((BEInt<T> *) (parent->head + link.position));
assert (0 == off);
check_assign (off, offset);
}

175
src/hb.hh
View File

@ -62,7 +62,6 @@
/* Error. Should never happen. */
#ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR
#pragma GCC diagnostic error "-Wc++11-narrowing"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
@ -75,6 +74,7 @@
#pragma GCC diagnostic error "-Wmissing-braces"
#pragma GCC diagnostic error "-Wmissing-declarations"
#pragma GCC diagnostic error "-Wmissing-prototypes"
#pragma GCC diagnostic error "-Wnarrowing"
#pragma GCC diagnostic error "-Wnested-externs"
#pragma GCC diagnostic error "-Wold-style-definition"
#pragma GCC diagnostic error "-Wpointer-arith"
@ -245,12 +245,8 @@ extern "C" void hb_free_impl(void *ptr);
#endif
#if defined(__GNUC__) && (__GNUC__ >= 3)
#define HB_PURE_FUNC __attribute__((pure))
#define HB_CONST_FUNC __attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
#define HB_PURE_FUNC
#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__)
@ -441,181 +437,12 @@ static int HB_UNUSED _hb_errno = 0;
#define HB_STMT_START do
#define HB_STMT_END while (0)
/* Static-assert as expression. */
template <unsigned int cond> class hb_assert_constant_t;
template <> class hb_assert_constant_t<1> {};
#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
/* Lets assert int types. Saves trouble down the road. */
static_assert ((sizeof (int8_t) == 1), "");
static_assert ((sizeof (uint8_t) == 1), "");
static_assert ((sizeof (int16_t) == 2), "");
static_assert ((sizeof (uint16_t) == 2), "");
static_assert ((sizeof (int32_t) == 4), "");
static_assert ((sizeof (uint32_t) == 4), "");
static_assert ((sizeof (int64_t) == 8), "");
static_assert ((sizeof (uint64_t) == 8), "");
static_assert ((sizeof (hb_codepoint_t) == 4), "");
static_assert ((sizeof (hb_position_t) == 4), "");
static_assert ((sizeof (hb_mask_t) == 4), "");
static_assert ((sizeof (hb_var_int_t) == 4), "");
#define HB_DELETE_COPY_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \
TypeName() = delete; \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
/* Flags */
/* 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++" { \
static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
} \
static_assert (true, "")
/* Useful for set-operations on small enums.
* For example, for testing "x ∈ {x1, x2, x3}" use:
* (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
*/
#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x)))
#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0)
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
#define FLAG64(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x)))
#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0)
/* Size signifying variable-sized array */
#ifndef HB_VAR_ARRAY
#define HB_VAR_ARRAY 1
#endif
static inline float
_hb_roundf (float x) { return floorf (x + .5f); }
#define roundf(x) _hb_roundf(x)
/* Endian swap, used in Windows related backends */
static inline uint16_t hb_uint16_swap (const uint16_t v)
{ return (v >> 8) | (v << 8); }
static inline uint32_t hb_uint32_swap (const uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
/*
* Big-endian integers. Here because fundamental.
*/
template <typename Type, int Bytes> struct BEInt;
template <typename Type>
struct BEInt<Type, 1>
{
public:
BEInt<Type, 1>& operator = (Type V)
{
v = V;
return *this;
}
operator Type () const { return v; }
private: uint8_t v;
};
template <typename Type>
struct BEInt<Type, 2>
{
public:
BEInt<Type, 2>& operator = (Type V)
{
v[0] = (V >> 8) & 0xFF;
v[1] = (V ) & 0xFF;
return *this;
}
operator Type () const
{
#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
defined(__BYTE_ORDER) && \
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
/* Spoon-feed the compiler a big-endian integer with alignment 1.
* https://github.com/harfbuzz/harfbuzz/pull/1398 */
struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
#if __BYTE_ORDER == __LITTLE_ENDIAN
return __builtin_bswap16 (((packed_uint16_t *) this)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
return ((packed_uint16_t *) this)->v;
#endif
#endif
return (v[0] << 8)
+ (v[1] );
}
private: uint8_t v[2];
};
template <typename Type>
struct BEInt<Type, 3>
{
public:
BEInt<Type, 3>& operator = (Type V)
{
v[0] = (V >> 16) & 0xFF;
v[1] = (V >> 8) & 0xFF;
v[2] = (V ) & 0xFF;
return *this;
}
operator Type () const
{
return (v[0] << 16)
+ (v[1] << 8)
+ (v[2] );
}
private: uint8_t v[3];
};
template <typename Type>
struct BEInt<Type, 4>
{
public:
BEInt<Type, 4>& operator = (Type V)
{
v[0] = (V >> 24) & 0xFF;
v[1] = (V >> 16) & 0xFF;
v[2] = (V >> 8) & 0xFF;
v[3] = (V ) & 0xFF;
return *this;
}
operator Type () const
{
return (v[0] << 24)
+ (v[1] << 16)
+ (v[2] << 8)
+ (v[3] );
}
private: uint8_t v[4];
};
/*
* For lack of a better place, put Zawgyi script hack here.
* https://github.com/harfbuzz/harfbuzz/issues/1162
*/
#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include