(root)/
fontconfig-2.14.2/
src/
fcserialize.c
       1  /*
       2   * Copyright © 2006 Keith Packard
       3   *
       4   * Permission to use, copy, modify, distribute, and sell this software and its
       5   * documentation for any purpose is hereby granted without fee, provided that
       6   * the above copyright notice appear in all copies and that both that copyright
       7   * notice and this permission notice appear in supporting documentation, and
       8   * that the name of the copyright holders not be used in advertising or
       9   * publicity pertaining to distribution of the software without specific,
      10   * written prior permission.  The copyright holders make no representations
      11   * about the suitability of this software for any purpose.  It is provided "as
      12   * is" without express or implied warranty.
      13   *
      14   * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      15   * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      16   * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      17   * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      18   * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      19   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      20   * OF THIS SOFTWARE.
      21   */
      22  
      23  #include "fcint.h"
      24  
      25  intptr_t
      26  FcAlignSize (intptr_t size)
      27  {
      28      intptr_t	rem = size % sizeof (FcAlign);
      29      if (rem)
      30  	size += sizeof (FcAlign) - rem;
      31      return size;
      32  }
      33  
      34  /*
      35   * Serialization helper object -- allocate space in the
      36   * yet-to-be-created linear array for a serialized font set
      37   */
      38  
      39  FcSerialize *
      40  FcSerializeCreate (void)
      41  {
      42      FcSerialize	*serialize;
      43  
      44      serialize = malloc (sizeof (FcSerialize));
      45      if (!serialize)
      46  	return NULL;
      47      serialize->size = 0;
      48      serialize->linear = NULL;
      49      serialize->cs_freezer = NULL;
      50      serialize->buckets = NULL;
      51      serialize->buckets_count = 0;
      52      serialize->buckets_used = 0;
      53      serialize->buckets_used_max = 0;
      54      return serialize;
      55  }
      56  
      57  void
      58  FcSerializeDestroy (FcSerialize *serialize)
      59  {
      60      free (serialize->buckets);
      61      if (serialize->cs_freezer)
      62  	FcCharSetFreezerDestroy (serialize->cs_freezer);
      63      free (serialize);
      64  }
      65  
      66  static size_t
      67  FcSerializeNextBucketIndex (const FcSerialize *serialize, size_t index)
      68  {
      69      if (index == 0)
      70  	index = serialize->buckets_count;
      71      --index;
      72      return index;
      73  }
      74  
      75  #if ((SIZEOF_VOID_P) * (CHAR_BIT)) == 32
      76  
      77  /*
      78   * Based on triple32
      79   * https://github.com/skeeto/hash-prospector
      80   */
      81  static uintptr_t
      82  FcSerializeHashPtr (const void *object)
      83  {
      84      uintptr_t x = (uintptr_t)object;
      85      x ^= x >> 17;
      86      x *= 0xed5ad4bbU;
      87      x ^= x >> 11;
      88      x *= 0xac4c1b51U;
      89      x ^= x >> 15;
      90      x *= 0x31848babU;
      91      x ^= x >> 14;
      92      return x ? x : 1; /* 0 reserved to mark empty, x starts out 0 */
      93  }
      94  
      95  
      96  #elif ((SIZEOF_VOID_P) * (CHAR_BIT)) == 64
      97  
      98  /*
      99   * Based on splittable64/splitmix64 from Mix13
     100   * https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
     101   * https://prng.di.unimi.it/splitmix64.c
     102   */
     103  static uintptr_t
     104  FcSerializeHashPtr (const void *object)
     105  {
     106      uintptr_t x = (uintptr_t)object;
     107      x ^= x >> 30;
     108      x *= 0xbf58476d1ce4e5b9U;
     109      x ^= x >> 27;
     110      x *= 0x94d049bb133111ebU;
     111      x ^= x >> 31;
     112      return x ? x : 1; /* 0 reserved to mark empty, x starts out 0 */
     113  }
     114  
     115  #endif
     116  
     117  static FcSerializeBucket*
     118  FcSerializeFind (const FcSerialize *serialize, const void *object)
     119  {
     120      uintptr_t hash = FcSerializeHashPtr (object);
     121      size_t buckets_count = serialize->buckets_count;
     122      size_t index = hash & (buckets_count-1);
     123      for (size_t n = 0; n < buckets_count; ++n) {
     124  	FcSerializeBucket* bucket = &serialize->buckets[index];
     125  	if (bucket->hash == 0) {
     126  	    return NULL;
     127  	}
     128  	if (object == bucket->object) {
     129  	    return bucket;
     130  	}
     131  	index = FcSerializeNextBucketIndex (serialize, index);
     132      }
     133      return NULL;
     134  }
     135  
     136  static FcSerializeBucket*
     137  FcSerializeUncheckedSet (FcSerialize *serialize, FcSerializeBucket* insert) {
     138      const void *object = insert->object;
     139      size_t buckets_count = serialize->buckets_count;
     140      size_t index = insert->hash & (buckets_count-1);
     141      for (size_t n = 0; n < buckets_count; ++n) {
     142  	FcSerializeBucket* bucket = &serialize->buckets[index];
     143  	if (bucket->hash == 0) {
     144  	    *bucket = *insert;
     145  	    ++serialize->buckets_used;
     146  	    return bucket;
     147  	}
     148  	if (object == bucket->object) {
     149  	    /* FcSerializeAlloc should not allow this to happen. */
     150  	    assert (0);
     151  	    *bucket = *insert;
     152  	    return bucket;
     153  	}
     154  	index = FcSerializeNextBucketIndex (serialize, index);
     155      }
     156      assert (0);
     157      return NULL;
     158  }
     159  
     160  static FcBool
     161  FcSerializeResize (FcSerialize *serialize, size_t new_count)
     162  {
     163      size_t old_used = serialize->buckets_used;
     164      size_t old_count = serialize->buckets_count;
     165      FcSerializeBucket *old_buckets = serialize->buckets;
     166      FcSerializeBucket *old_buckets_end = old_buckets + old_count;
     167  
     168      FcSerializeBucket *new_buckets = malloc (new_count * sizeof (*old_buckets));
     169      if (!new_buckets)
     170  	return FcFalse;
     171      FcSerializeBucket *new_buckets_end = new_buckets + new_count;
     172      for (FcSerializeBucket *b = new_buckets; b < new_buckets_end; ++b)
     173  	b->hash = 0;
     174  
     175      serialize->buckets = new_buckets;
     176      serialize->buckets_count = new_count;
     177      serialize->buckets_used = 0;
     178      for (FcSerializeBucket *b = old_buckets; b < old_buckets_end; ++b)
     179  	if (b->hash != 0 && !FcSerializeUncheckedSet (serialize, b))
     180  	{
     181  	    serialize->buckets = old_buckets;
     182  	    serialize->buckets_count = old_count;
     183  	    serialize->buckets_used = old_used;
     184  	    free (new_buckets);
     185  	    return FcFalse;
     186  	}
     187      free (old_buckets);
     188      return FcTrue;
     189  }
     190  
     191  static FcSerializeBucket*
     192  FcSerializeSet (FcSerialize *serialize, const void *object, intptr_t offset)
     193  {
     194      if (serialize->buckets_used >= serialize->buckets_used_max)
     195      {
     196  	size_t capacity = serialize->buckets_count;
     197  	if (capacity == 0)
     198  	    capacity = 4;
     199  	else if (capacity > SIZE_MAX / 2u)
     200  	    return NULL;
     201  	else
     202  	    capacity *= 2;
     203  
     204  	if (!FcSerializeResize (serialize, capacity))
     205  	    return NULL;
     206  
     207  	serialize->buckets_used_max = capacity / 4u * 3u;
     208      }
     209  
     210      FcSerializeBucket bucket;
     211      bucket.object = object;
     212      bucket.offset = offset;
     213      bucket.hash = FcSerializeHashPtr (object);
     214      return FcSerializeUncheckedSet (serialize, &bucket);
     215  }
     216  
     217  /*
     218   * Allocate space for an object in the serialized array. Keep track
     219   * of where the object is placed and only allocate one copy of each object
     220   */
     221  FcBool
     222  FcSerializeAlloc (FcSerialize *serialize, const void *object, int size)
     223  {
     224      FcSerializeBucket *bucket = FcSerializeFind (serialize, object);
     225      if (bucket)
     226  	return FcTrue;
     227  
     228      if (!FcSerializeSet (serialize, object, serialize->size))
     229  	return FcFalse;
     230  
     231      serialize->size += FcAlignSize (size);
     232      return FcTrue;
     233  }
     234  
     235  /*
     236   * Reserve space in the serialization array
     237   */
     238  intptr_t
     239  FcSerializeReserve (FcSerialize *serialize, int size)
     240  {
     241      intptr_t	offset = serialize->size;
     242      serialize->size += FcAlignSize (size);
     243      return offset;
     244  }
     245  
     246  /*
     247   * Given an object, return the offset in the serialized array where
     248   * the serialized copy of the object is stored
     249   */
     250  intptr_t
     251  FcSerializeOffset (FcSerialize *serialize, const void *object)
     252  {
     253      FcSerializeBucket *bucket = FcSerializeFind (serialize, object);
     254      return bucket ? bucket->offset : 0;
     255  }
     256  
     257  /*
     258   * Given a cache and an object, return a pointer to where
     259   * the serialized copy of the object is stored
     260   */
     261  void *
     262  FcSerializePtr (FcSerialize *serialize, const void *object)
     263  {
     264      intptr_t	offset = FcSerializeOffset (serialize, object);
     265  
     266      if (!offset)
     267  	return NULL;
     268      return (void *) ((char *) serialize->linear + offset);
     269  }
     270  
     271  FcBool
     272  FcStrSerializeAlloc (FcSerialize *serialize, const FcChar8 *str)
     273  {
     274      return FcSerializeAlloc (serialize, str, strlen ((const char *) str) + 1);
     275  }
     276  
     277  FcChar8 *
     278  FcStrSerialize (FcSerialize *serialize, const FcChar8 *str)
     279  {
     280      FcChar8 *str_serialize = FcSerializePtr (serialize, str);
     281      if (!str_serialize)
     282  	return NULL;
     283      strcpy ((char *) str_serialize, (const char *) str);
     284      return str_serialize;
     285  }
     286  #include "fcaliastail.h"
     287  #undef __fcserialize__