Imported Upstream version 1.8.1
[platform/upstream/harfbuzz.git] / src / hb-private.hh
index daa496e..32e3354 100644 (file)
@@ -51,7 +51,7 @@
 #include <stdio.h>
 #include <stdarg.h>
 
-#if defined(_MSC_VER) || defined(__MINGW32__)
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
 #include <intrin.h>
 #endif
 
@@ -90,6 +90,14 @@ extern "C" void  hb_free_impl(void *ptr);
        HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
 #endif // static_assert
 
+#ifdef __GNUC__
+#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
+#define thread_local __thread
+#endif
+#else
+#define thread_local
+#endif
+
 #endif // __cplusplus < 201103L
 
 #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
@@ -139,7 +147,7 @@ extern "C" void  hb_free_impl(void *ptr);
 #define HB_FUNC __func__
 #endif
 
-#ifdef __SUNPRO_CC
+#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140)
 /* https://github.com/harfbuzz/harfbuzz/issues/630 */
 #define __restrict
 #endif
@@ -221,16 +229,14 @@ static int errno = 0; /* Use something better? */
 #    endif
 #  elif defined(_MSC_VER) || defined(__MINGW32__)
 /* For MSVC:
- * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
- * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
+ * https://msdn.microsoft.com/en-us/library/tze57ck3.aspx
+ * https://msdn.microsoft.com/en-us/library/zk17ww08.aspx
  * mingw32 headers say atexit is safe to use in shared libraries.
  */
 #    define HB_USE_ATEXIT 1
-#  elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-/* This was fixed in Android NKD r8 or r8b:
- * https://code.google.com/p/android/issues/detail?id=6455
- * which introduced GCC 4.6:
- * https://developer.android.com/tools/sdk/ndk/index.html
+#  elif defined(__ANDROID__)
+/* This is available since Android NKD r8 or r8b:
+ * https://issuetracker.google.com/code/p/android/issues/detail?id=6455
  */
 #    define HB_USE_ATEXIT 1
 #  elif defined(__APPLE__)
@@ -241,6 +247,9 @@ static int errno = 0; /* Use something better? */
 #    define HB_USE_ATEXIT 1
 #  endif
 #endif
+#ifdef HB_NO_ATEXIT
+#  undef HB_USE_ATEXIT
+#endif
 
 /* Basics */
 
@@ -314,7 +323,7 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
 
 
 
-/* Misc */
+/* Tiny functions */
 
 /*
  * Void!
@@ -360,6 +369,7 @@ _hb_popcount (T v)
   }
 
   assert (0);
+  return 0; /* Shut up stupid compiler. */
 }
 
 /* Returns the number of bits needed to store number */
@@ -380,7 +390,7 @@ _hb_bit_storage (T v)
     return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
 #endif
 
-#if defined(_MSC_VER) || defined(__MINGW32__)
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
   if (sizeof (T) <= sizeof (unsigned int))
   {
     unsigned long where;
@@ -414,7 +424,7 @@ _hb_bit_storage (T v)
   if (sizeof (T) <= 8)
   {
     /* "bithacks" */
-    const uint64_t b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000};
+    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
     const unsigned int S[] = {1, 2, 4, 8, 16, 32};
     unsigned int r = 0;
     for (int i = 5; i >= 0; i--)
@@ -428,11 +438,12 @@ _hb_bit_storage (T v)
   if (sizeof (T) == 16)
   {
     unsigned int shift = 64;
-    return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) v >> shift) + shift :
+    return (v >> shift) ? _hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
                          _hb_bit_storage<uint64_t> ((uint64_t) v);
   }
 
   assert (0);
+  return 0; /* Shut up stupid compiler. */
 }
 
 /* Returns the number of zero bits in the least significant side of v */
@@ -453,7 +464,7 @@ _hb_ctz (T v)
     return __builtin_ctzll (v);
 #endif
 
-#if defined(_MSC_VER) || defined(__MINGW32__)
+#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
   if (sizeof (T) <= sizeof (unsigned int))
   {
     unsigned long where;
@@ -489,12 +500,12 @@ _hb_ctz (T v)
     unsigned int c = 64;
     v &= - (int64_t) (v);
     if (v) c--;
-    if (v & 0x00000000FFFFFFFF) c -= 32;
-    if (v & 0x0000FFFF0000FFFF) c -= 16;
-    if (v & 0x00FF00FF00FF00FF) c -= 8;
-    if (v & 0x0F0F0F0F0F0F0F0F) c -= 4;
-    if (v & 0x3333333333333333) c -= 2;
-    if (v & 0x5555555555555555) c -= 1;
+    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)
@@ -505,6 +516,7 @@ _hb_ctz (T v)
   }
 
   assert (0);
+  return 0; /* Shut up stupid compiler. */
 }
 
 static inline bool
@@ -521,39 +533,147 @@ _hb_ceil_to_4 (unsigned int v)
 
 
 
+/*
+ *
+ * Utility types
+ *
+ */
+
+#define HB_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&); \
+  void operator=(const TypeName&)
+
+/*
+ * Static pools
+ */
+
+/* Global nul-content Null pool.  Enlarge as necessary. */
+
+#define HB_NULL_POOL_SIZE 264
+static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE.");
+
+#ifdef HB_NO_VISIBILITY
+static
+#else
+extern HB_INTERNAL
+#endif
+void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)]
+#ifdef HB_NO_VISIBILITY
+= {}
+#endif
+;
+/* Generic nul-content Null objects. */
+template <typename Type>
+static inline Type const & Null (void) {
+  static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
+  return *reinterpret_cast<Type const *> (_hb_NullPool);
+}
+#define Null(Type) Null<Type>()
+
+/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
+#define DEFINE_NULL_DATA(Namespace, Type, data) \
+} /* Close namespace. */ \
+static const char _Null##Type[sizeof (Namespace::Type) + 1] = data; /* +1 is for nul-termination in data */ \
+template <> \
+/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
+  return *reinterpret_cast<const Namespace::Type *> (_Null##Type); \
+} \
+namespace Namespace { \
+/* The following line really exists such that we end in a place needing semicolon */ \
+static_assert (Namespace::Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small.  Enlarge.")
+
+
+/* Global writable pool.  Enlarge as necessary. */
+
+/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
+ * for correct operation. It only exist to catch and divert program logic bugs instead of
+ * causing bad memory access. So, races there are not actually introducing incorrectness
+ * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
+#ifdef HB_NO_VISIBILITY
+static
+#else
+extern HB_INTERNAL
+#endif
+/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)]
+#ifdef HB_NO_VISIBILITY
+= {}
+#endif
+;
+/* CRAP pool: Common Region for Access Protection. */
+template <typename Type>
+static inline Type& Crap (void) {
+  static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
+  Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
+  *obj = Null(Type);
+  return *obj;
+}
+#define Crap(Type) Crap<Type>()
+
+template <typename Type>
+struct CrapOrNull {
+  static inline Type & get (void) { return Crap(Type); }
+};
+template <typename Type>
+struct CrapOrNull<const Type> {
+  static inline Type const & get (void) { return Null(Type); }
+};
+#define CrapOrNull(Type) CrapOrNull<Type>::get ()
+
+
+
 /* arrays and maps */
 
 
 #define HB_PREALLOCED_ARRAY_INIT {0, 0, nullptr}
-template <typename Type, unsigned int StaticSize=16>
-struct hb_prealloced_array_t
+template <typename Type, unsigned int StaticSize=8>
+struct hb_vector_t
 {
   unsigned int len;
   unsigned int allocated;
-  Type *array;
+  bool successful;
+  Type *arrayZ;
   Type static_array[StaticSize];
 
   void init (void)
   {
     len = 0;
     allocated = ARRAY_LENGTH (static_array);
-    array = static_array;
+    successful = true;
+    arrayZ = static_array;
   }
 
-  inline Type& operator [] (unsigned int i) { return array[i]; }
-  inline const Type& operator [] (unsigned int i) const { return array[i]; }
+  inline Type& operator [] (unsigned int i)
+  {
+    if (unlikely (i >= len))
+      return Crap (Type);
+    return arrayZ[i];
+  }
+  inline const Type& operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= len))
+      return Null(Type);
+    return arrayZ[i];
+  }
 
   inline Type *push (void)
   {
     if (unlikely (!resize (len + 1)))
-      return nullptr;
-
-    return &array[len - 1];
+      return &Crap(Type);
+    return &arrayZ[len - 1];
+  }
+  inline Type *push (const Type& v)
+  {
+    Type *p = push ();
+    *p = v;
+    return p;
   }
 
   /* Allocate for size but don't adjust len. */
-  inline bool alloc(unsigned int size)
+  inline bool alloc (unsigned int size)
   {
+    if (unlikely (!successful))
+      return false;
+
     if (likely (size <= allocated))
       return true;
 
@@ -565,37 +685,47 @@ struct hb_prealloced_array_t
 
     Type *new_array = nullptr;
 
-    if (array == static_array) {
+    if (arrayZ == static_array)
+    {
       new_array = (Type *) calloc (new_allocated, sizeof (Type));
       if (new_array)
-        memcpy (new_array, array, len * sizeof (Type));
-          } else {
+        memcpy (new_array, arrayZ, len * sizeof (Type));
+    }
+    else
+    {
       bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type));
-      if (likely (!overflows)) {
-        new_array = (Type *) realloc (array, new_allocated * sizeof (Type));
-      }
+      if (likely (!overflows))
+        new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
     }
 
     if (unlikely (!new_array))
+    {
+      successful = false;
       return false;
+    }
 
-    array = new_array;
+    arrayZ = new_array;
     allocated = new_allocated;
 
     return true;
   }
 
-  inline bool resize (unsigned int size)
+  inline bool resize (int size_)
   {
+    unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
     if (!alloc (size))
       return false;
 
+    if (size > len)
+      memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
+
     len = size;
     return true;
   }
 
   inline void pop (void)
   {
+    if (!len) return;
     len--;
   }
 
@@ -603,54 +733,55 @@ struct hb_prealloced_array_t
   {
      if (unlikely (i >= len))
        return;
-     memmove (static_cast<void *> (&array[i]),
-             static_cast<void *> (&array[i + 1]),
+     memmove (static_cast<void *> (&arrayZ[i]),
+             static_cast<void *> (&arrayZ[i + 1]),
              (len - i - 1) * sizeof (Type));
      len--;
   }
 
-  inline void shrink (unsigned int l)
+  inline void shrink (int size_)
   {
-     if (l < len)
-       len = l;
+    unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
+     if (size < len)
+       len = size;
   }
 
   template <typename T>
   inline Type *find (T v) {
     for (unsigned int i = 0; i < len; i++)
-      if (array[i] == v)
-       return &array[i];
+      if (arrayZ[i] == v)
+       return &arrayZ[i];
     return nullptr;
   }
   template <typename T>
   inline const Type *find (T v) const {
     for (unsigned int i = 0; i < len; i++)
-      if (array[i] == v)
-       return &array[i];
+      if (arrayZ[i] == v)
+       return &arrayZ[i];
     return nullptr;
   }
 
   inline void qsort (int (*cmp)(const void*, const void*))
   {
-    ::qsort (array, len, sizeof (Type), cmp);
+    ::qsort (arrayZ, len, sizeof (Type), cmp);
   }
 
   inline void qsort (void)
   {
-    ::qsort (array, len, sizeof (Type), Type::cmp);
+    ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
   }
 
   inline void qsort (unsigned int start, unsigned int end)
   {
-    ::qsort (array + start, end - start, sizeof (Type), Type::cmp);
+    ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
   }
 
   template <typename T>
   inline Type *lsearch (const T &x)
   {
     for (unsigned int i = 0; i < len; i++)
-      if (0 == this->array[i].cmp (&x))
-       return &array[i];
+      if (0 == this->arrayZ[i].cmp (&x))
+       return &arrayZ[i];
     return nullptr;
   }
 
@@ -658,13 +789,13 @@ struct hb_prealloced_array_t
   inline Type *bsearch (const T &x)
   {
     unsigned int i;
-    return bfind (x, &i) ? &array[i] : nullptr;
+    return bfind (x, &i) ? &arrayZ[i] : nullptr;
   }
   template <typename T>
   inline const Type *bsearch (const T &x) const
   {
     unsigned int i;
-    return bfind (x, &i) ? &array[i] : nullptr;
+    return bfind (x, &i) ? &arrayZ[i] : nullptr;
   }
   template <typename T>
   inline bool bfind (const T &x, unsigned int *i) const
@@ -673,7 +804,7 @@ struct hb_prealloced_array_t
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      int c = this->array[mid].cmp (&x);
+      int c = this->arrayZ[mid].cmp (&x);
       if (c < 0)
         max = mid - 1;
       else if (c > 0)
@@ -684,34 +815,39 @@ struct hb_prealloced_array_t
        return true;
       }
     }
-    if (max < 0 || (max < (int) this->len && this->array[max].cmp (&x) > 0))
+    if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
       max++;
     *i = max;
     return false;
   }
 
-  inline void finish (void)
+  inline void fini (void)
   {
-    if (array != static_array)
-      free (array);
-    array = nullptr;
+    if (arrayZ != static_array)
+      free (arrayZ);
+    arrayZ = nullptr;
     allocated = len = 0;
   }
 };
 
 template <typename Type>
-struct hb_auto_array_t : hb_prealloced_array_t <Type>
+struct hb_auto_t : Type
 {
-  hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
-  ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
+  hb_auto_t (void) { Type::init (); }
+  ~hb_auto_t (void) { Type::fini (); }
+  private: /* Hide */
+  void init (void) {}
+  void fini (void) {}
 };
+template <typename Type>
+struct hb_auto_array_t : hb_auto_t <hb_vector_t <Type> > {};
 
 
 #define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
 template <typename item_t, typename lock_t>
 struct hb_lockable_set_t
 {
-  hb_prealloced_array_t <item_t, 1> items;
+  hb_vector_t <item_t, 1> items;
 
   inline void init (void) { items.init (); }
 
@@ -725,16 +861,14 @@ struct hb_lockable_set_t
        item_t old = *item;
        *item = v;
        l.unlock ();
-       old.finish ();
+       old.fini ();
       }
       else {
         item = nullptr;
        l.unlock ();
       }
     } else {
-      item = items.push ();
-      if (likely (item))
-       *item = v;
+      item = items.push (v);
       l.unlock ();
     }
     return item;
@@ -750,7 +884,7 @@ struct hb_lockable_set_t
       *item = items[items.len - 1];
       items.pop ();
       l.unlock ();
-      old.finish ();
+      old.fini ();
     } else {
       l.unlock ();
     }
@@ -773,19 +907,17 @@ struct hb_lockable_set_t
     l.lock ();
     item_t *item = items.find (v);
     if (!item) {
-      item = items.push ();
-      if (likely (item))
-        *item = v;
+      item = items.push (v);
     }
     l.unlock ();
     return item;
   }
 
-  inline void finish (lock_t &l)
+  inline void fini (lock_t &l)
   {
     if (!items.len) {
       /* No need for locking. */
-      items.finish ();
+      items.fini ();
       return;
     }
     l.lock ();
@@ -793,10 +925,10 @@ struct hb_lockable_set_t
       item_t old = items[items.len - 1];
        items.pop ();
        l.unlock ();
-       old.finish ();
+       old.fini ();
        l.lock ();
     }
-    items.finish ();
+    items.fini ();
     l.unlock ();
   }
 
@@ -823,7 +955,7 @@ static inline unsigned char TOLOWER (unsigned char c)
  * light-weight) to be enabled, then HB_DEBUG can be defined to disable
  * the costlier checks. */
 #ifdef NDEBUG
-#define HB_NDEBUG
+#define HB_NDEBUG 1
 #endif
 
 
@@ -972,19 +1104,35 @@ struct HbOpXor
   template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
 };
 
+
+/* Compiler-assisted vectorization. */
+
+/* The `vector_size' attribute was introduced in gcc 3.1. */
+#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
+#define HB_VECTOR_SIZE 128
+#elif !defined(HB_VECTOR_SIZE)
+#define HB_VECTOR_SIZE 0
+#endif
+
 /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))). */
 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]; }
+  elt_t& operator [] (unsigned int i) { return u.v[i]; }
+  const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
 
   template <class Op>
   inline hb_vector_size_t process (const hb_vector_size_t &o) const
   {
     hb_vector_size_t r;
-    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
-      Op::process (r.v[i], v[i], o.v[i]);
+#if HB_VECTOR_SIZE
+    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
+      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
+       Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
+    else
+#endif
+      for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
+       Op::process (r.u.v[i], u.v[i], o.u.v[i]);
     return r;
   }
   inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
@@ -996,20 +1144,27 @@ struct hb_vector_size_t
   inline hb_vector_size_t operator ~ () const
   {
     hb_vector_size_t r;
-    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
-      r.v[i] = ~v[i];
+#if HB_VECTOR_SIZE && 0
+    if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
+      for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
+       r.u.vec[i] = ~u.vec[i];
+    else
+#endif
+    for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
+      r.u.v[i] = ~u.v[i];
     return r;
   }
 
   private:
   static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
-  elt_t v[byte_size / sizeof (elt_t)];
-};
-
-/* The `vector_size' attribute was introduced in gcc 3.1. */
-#if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
-#define HAVE_VECTOR_SIZE 1
+  union {
+    elt_t v[byte_size / sizeof (elt_t)];
+#if HB_VECTOR_SIZE
+    typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
+    vec_t vec[byte_size / sizeof (vec_t)];
 #endif
+  } u;
+};
 
 
 /* Global runtime options. */
@@ -1046,12 +1201,12 @@ hb_options (void)
 
 /* String type. */
 
-struct hb_string_t
+struct hb_bytes_t
 {
-  inline hb_string_t (void) : bytes (nullptr), len (0) {}
-  inline hb_string_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
+  inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
+  inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
 
-  inline int cmp (const hb_string_t &a) const
+  inline int cmp (const hb_bytes_t &a) const
   {
     if (len != a.len)
       return (int) a.len - (int) len;
@@ -1060,8 +1215,8 @@ struct hb_string_t
   }
   static inline int cmp (const void *pa, const void *pb)
   {
-    hb_string_t *a = (hb_string_t *) pa;
-    hb_string_t *b = (hb_string_t *) pb;
+    hb_bytes_t *a = (hb_bytes_t *) pa;
+    hb_bytes_t *b = (hb_bytes_t *) pb;
     return b->cmp (*a);
   }
 
@@ -1070,4 +1225,17 @@ struct hb_string_t
 };
 
 
+/* fallback for round() */
+#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND)
+static inline double
+round (double x)
+{
+  if (x >= 0)
+    return floor (x + 0.5);
+  else
+    return ceil (x - 0.5);
+}
+#endif
+
+
 #endif /* HB_PRIVATE_HH */