diff --git a/.circleci/config.yml b/.circleci/config.yml index 26fa93971..d5e7de213 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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: . diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index a2c311f9c..6fcb4e5ef 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -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 \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 11118595f..ec5fac7f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 - /* This requires Solaris Studio 12.2 or newer: */ - #include - 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}) diff --git a/Makefile.am b/Makefile.am index f476c964f..9f34c5f1a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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) diff --git a/configure.ac b/configure.ac index 2e16b4861..14199272e 100644 --- a/configure.ac +++ b/configure.ac @@ -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 - /* This requires Solaris Studio 12.2 or newer: */ - #include - 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 diff --git a/meson-cc-tests/intel-atomic-primitives-test.c b/meson-cc-tests/intel-atomic-primitives-test.c deleted file mode 100644 index a5c804091..000000000 --- a/meson-cc-tests/intel-atomic-primitives-test.c +++ /dev/null @@ -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;} diff --git a/meson-cc-tests/solaris-atomic-operations.c b/meson-cc-tests/solaris-atomic-operations.c deleted file mode 100644 index fae0acd87..000000000 --- a/meson-cc-tests/solaris-atomic-operations.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -/* This requires Solaris Studio 12.2 or newer: */ -#include -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; } diff --git a/meson.build b/meson.build index 83c179967..2099e136b 100644 --- a/meson.build +++ b/meson.build @@ -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') diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 5b9c14e62..05c98ef20 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -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 struct BEInt; +template +struct BEInt +{ + public: + BEInt () = default; + constexpr BEInt (Type V) : v {uint8_t (V)} {} + constexpr operator Type () const { return v; } + private: uint8_t v; +}; +template +struct BEInt +{ + 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 +struct BEInt +{ + 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 +struct BEInt +{ + 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 -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 -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 -static inline HB_CONST_FUNC unsigned int +static inline unsigned int hb_ctz (T v) { if (unlikely (!v)) return 8 * sizeof (T); diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh index b3fb296b4..93265f655 100644 --- a/src/hb-atomic.hh +++ b/src/hb-atomic.hh @@ -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 - -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 -#include - -#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 -#ifdef __MAC_OS_X_MIN_REQUIRED -#include -#elif defined(__IPHONE_OS_MIN_REQUIRED) -#include -#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 - -#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 struct hb_atomic_ptr_t { typedef hb_remove_pointer

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 operator C * () const { return get (); } - T *v; + T *v = nullptr; }; diff --git a/src/hb-face.cc b/src/hb-face.cc index 900014fae..61bd4af7b 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -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. */ }; diff --git a/src/hb-face.hh b/src/hb-face.hh index f1b472ccf..765f27285 100644 --- a/src/hb-face.hh +++ b/src/hb-face.hh @@ -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)) diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index 54bc60d4c..3bd5a979b 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -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 \ diff --git a/src/hb-meta.hh b/src/hb-meta.hh index 4c0898b1b..e40d9fd17 100644 --- a/src/hb-meta.hh +++ b/src/hb-meta.hh @@ -49,6 +49,10 @@ template using hb_bool_constant = hb_integral_constant; using hb_true_type = hb_bool_constant; using hb_false_type = hb_bool_constant; +/* Static-assert as expression. */ +template struct static_assert_expr; +template <> struct static_assert_expr : hb_false_type {}; +#define static_assert_expr(C) static_assert_expr::value /* Basic type SFINAE. */ @@ -220,6 +224,8 @@ struct hb_reference_wrapper }; +/* Type traits */ + template using hb_is_integral = hb_bool_constant< hb_is_same (hb_decay, char) || @@ -292,6 +298,15 @@ template <> struct hb_int_max : hb_integral_constant::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 struct _hb_is_destructible : hb_false_type {}; diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh index 56392d049..2fc8d7ee5 100644 --- a/src/hb-mutex.hh +++ b/src/hb-mutex.hh @@ -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 -# 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; diff --git a/src/hb-object.hh b/src/hb-object.hh index 39845a70e..f3048b1c3 100644 --- a/src/hb-object.hh +++ b/src/hb-object.hh @@ -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 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 {} /* diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index 8c4271b68..478bb60ac 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -53,7 +53,7 @@ namespace OT { */ /* Integer types in big-endian order and no alignment requirement */ -template +template struct IntType { typedef Type type; @@ -107,12 +107,12 @@ struct IntType DEFINE_SIZE_STATIC (Size); }; -typedef IntType HBUINT8; /* 8-bit unsigned integer. */ -typedef IntType HBINT8; /* 8-bit signed integer. */ -typedef IntType HBUINT16; /* 16-bit unsigned integer. */ -typedef IntType HBINT16; /* 16-bit signed integer. */ -typedef IntType HBUINT32; /* 32-bit unsigned integer. */ -typedef IntType HBINT32; /* 32-bit signed integer. */ +typedef IntType HBUINT8; /* 8-bit unsigned integer. */ +typedef IntType HBINT8; /* 8-bit signed integer. */ +typedef IntType HBUINT16; /* 16-bit unsigned integer. */ +typedef IntType HBINT16; /* 16-bit signed integer. */ +typedef IntType HBUINT32; /* 32-bit unsigned integer. */ +typedef IntType 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 HBUINT24; /* 24-bit unsigned integer. */ diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh index b15e145f2..41e3dd38a 100644 --- a/src/hb-ot-shape-complex-arabic-win1256.hh +++ b/src/hb-ot-shape-complex-arabic-win1256.hh @@ -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)) diff --git a/src/hb-ot-shape-complex-indic.hh b/src/hb-ot-shape-complex-indic.hh index 63dc93ea9..dcb28a4e8 100644 --- a/src/hb-ot-shape-complex-indic.hh +++ b/src/hb-ot-shape-complex-indic.hh @@ -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 | \ ( \ ( \ diff --git a/src/hb-ot-shape-complex.hh b/src/hb-ot-shape-complex.hh index b592cad10..19e24b9f3 100644 --- a/src/hb-ot-shape-complex.hh +++ b/src/hb-ot-shape-complex.hh @@ -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; diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index 7238fb0d8..fe29bdf96 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -524,7 +524,7 @@ struct hb_serialize_context_t template void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) { - auto &off = * ((BEInt *) (parent->head + link.position)); + auto &off = * ((BEInt *) (parent->head + link.position)); assert (0 == off); check_assign (off, offset); } diff --git a/src/hb.hh b/src/hb.hh index ef735583f..31a6287a8 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -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 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 struct BEInt; - -template -struct BEInt -{ - public: - BEInt& operator = (Type V) - { - v = V; - return *this; - } - operator Type () const { return v; } - private: uint8_t v; -}; -template -struct BEInt -{ - public: - BEInt& 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 -struct BEInt -{ - public: - BEInt& 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 -struct BEInt -{ - public: - BEInt& 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