Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-cache.hh
Line
Count
Source
1
/*
2
 * Copyright © 2012  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod
25
 */
26
27
#ifndef HB_CACHE_HH
28
#define HB_CACHE_HH
29
30
#include "hb.hh"
31
32
33
/* Implements a lockfree and thread-safe cache for int->int functions,
34
 * using (optionally) _relaxed_ atomic integer operations.
35
 *
36
 * The cache is a fixed-size array of 16-bit or 32-bit integers,
37
 * typically 256 elements.
38
 *
39
 * The key is split into two parts: the cache index (high bits)
40
 * and the rest (low bits).
41
 *
42
 * The cache index is used to index into the array.  The array
43
 * member is a 16-bit or 32-bit integer that is used *both*
44
 * to store the low bits of the key, and the value.
45
 *
46
 * The value is stored in the least significant bits of the integer.
47
 * The low bits of the key are stored in the most significant bits
48
 * of the integer.
49
 *
50
 * A cache hit is detected by comparing the low bits of the key
51
 * with the high bits of the integer at the array position indexed
52
 * by the high bits of the key. If they match, the value is extracted
53
 * from the least significant bits of the integer and returned.
54
 * Otherwise, a cache miss is reported.
55
 *
56
 * Cache operations (storage and retrieval) involve just a few
57
 * arithmetic operations and a single memory access.
58
 */
59
60
template <unsigned int key_bits=16,
61
   unsigned int value_bits=8 + 32 - key_bits,
62
   unsigned int cache_bits=8,
63
   bool thread_safe=true>
64
struct hb_cache_t
65
{
66
  using item_t = typename std::conditional<thread_safe,
67
             typename std::conditional<key_bits + value_bits - cache_bits <= 8,
68
                     hb_atomic_t<unsigned char>,
69
                     typename std::conditional<key_bits + value_bits - cache_bits <= 16,
70
                             hb_atomic_t<unsigned short>,
71
                             hb_atomic_t<unsigned int>>::type>::type,
72
             typename std::conditional<key_bits + value_bits - cache_bits <= 8,
73
                     unsigned char,
74
                     typename std::conditional<key_bits + value_bits - cache_bits <= 16,
75
                             unsigned short,
76
                             unsigned int>::type>::type
77
            >::type;
78
79
  static_assert ((key_bits >= cache_bits), "");
80
  static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
81
82
  static constexpr unsigned MAX_VALUE = (1u << value_bits) - 1;
83
84
38.9k
  hb_cache_t () { clear (); }
hb_cache_t<21u, 3u, 8u, true>::hb_cache_t()
Line
Count
Source
84
9.02k
  hb_cache_t () { clear (); }
hb_cache_t<16u, 8u, 8u, true>::hb_cache_t()
Line
Count
Source
84
428
  hb_cache_t () { clear (); }
hb_cache_t<21u, 19u, 8u, true>::hb_cache_t()
Line
Count
Source
84
29.0k
  hb_cache_t () { clear (); }
Unexecuted instantiation: hb_cache_t<24u, 16u, 8u, true>::hb_cache_t()
hb_cache_t<20u, 20u, 8u, true>::hb_cache_t()
Line
Count
Source
84
405
  hb_cache_t () { clear (); }
85
86
  void clear ()
87
39.9k
  {
88
39.9k
    for (auto &v : values)
89
10.2M
      v = -1;
90
39.9k
  }
hb_cache_t<21u, 3u, 8u, true>::clear()
Line
Count
Source
87
9.02k
  {
88
9.02k
    for (auto &v : values)
89
2.31M
      v = -1;
90
9.02k
  }
hb_cache_t<16u, 8u, 8u, true>::clear()
Line
Count
Source
87
1.34k
  {
88
1.34k
    for (auto &v : values)
89
343k
      v = -1;
90
1.34k
  }
hb_cache_t<14u, 1u, 8u, true>::clear()
Line
Count
Source
87
110
  {
88
110
    for (auto &v : values)
89
28.1k
      v = -1;
90
110
  }
hb_cache_t<21u, 19u, 8u, true>::clear()
Line
Count
Source
87
29.0k
  {
88
29.0k
    for (auto &v : values)
89
7.43M
      v = -1;
90
29.0k
  }
Unexecuted instantiation: hb_cache_t<24u, 16u, 8u, true>::clear()
hb_cache_t<20u, 20u, 8u, true>::clear()
Line
Count
Source
87
405
  {
88
405
    for (auto &v : values)
89
103k
      v = -1;
90
405
  }
91
92
  HB_HOT
93
  bool get (unsigned int key, unsigned int *value) const
94
760M
  {
95
760M
    unsigned int k = key & ((1u<<cache_bits)-1);
96
760M
    unsigned int v = values[k];
97
760M
    constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1;
98
    /* Combine overflow, tag mismatch, and empty checks into one branch. */
99
760M
    if ((key >> key_bits) |
100
760M
  ((v >> value_bits) ^ (key >> cache_bits)) |
101
760M
  ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty)))
102
45.6M
      return false;
103
714M
    *value = v & ((1u<<value_bits)-1);
104
714M
    return true;
105
760M
  }
hb_cache_t<16u, 8u, 8u, true>::get(unsigned int, unsigned int*) const
Line
Count
Source
94
172M
  {
95
172M
    unsigned int k = key & ((1u<<cache_bits)-1);
96
172M
    unsigned int v = values[k];
97
172M
    constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1;
98
    /* Combine overflow, tag mismatch, and empty checks into one branch. */
99
172M
    if ((key >> key_bits) |
100
172M
  ((v >> value_bits) ^ (key >> cache_bits)) |
101
172M
  ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty)))
102
247k
      return false;
103
172M
    *value = v & ((1u<<value_bits)-1);
104
172M
    return true;
105
172M
  }
hb_cache_t<21u, 3u, 8u, true>::get(unsigned int, unsigned int*) const
Line
Count
Source
94
284M
  {
95
284M
    unsigned int k = key & ((1u<<cache_bits)-1);
96
284M
    unsigned int v = values[k];
97
284M
    constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1;
98
    /* Combine overflow, tag mismatch, and empty checks into one branch. */
99
284M
    if ((key >> key_bits) |
100
284M
  ((v >> value_bits) ^ (key >> cache_bits)) |
101
284M
  ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty)))
102
1.56M
      return false;
103
282M
    *value = v & ((1u<<value_bits)-1);
104
282M
    return true;
105
284M
  }
hb_cache_t<14u, 1u, 8u, true>::get(unsigned int, unsigned int*) const
Line
Count
Source
94
147k
  {
95
147k
    unsigned int k = key & ((1u<<cache_bits)-1);
96
147k
    unsigned int v = values[k];
97
147k
    constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1;
98
    /* Combine overflow, tag mismatch, and empty checks into one branch. */
99
147k
    if ((key >> key_bits) |
100
147k
  ((v >> value_bits) ^ (key >> cache_bits)) |
101
147k
  ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty)))
102
15.5k
      return false;
103
132k
    *value = v & ((1u<<value_bits)-1);
104
132k
    return true;
105
147k
  }
hb_cache_t<21u, 19u, 8u, true>::get(unsigned int, unsigned int*) const
Line
Count
Source
94
303M
  {
95
303M
    unsigned int k = key & ((1u<<cache_bits)-1);
96
303M
    unsigned int v = values[k];
97
303M
    constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1;
98
    /* Combine overflow, tag mismatch, and empty checks into one branch. */
99
303M
    if ((key >> key_bits) |
100
303M
  ((v >> value_bits) ^ (key >> cache_bits)) |
101
303M
  ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty)))
102
43.8M
      return false;
103
259M
    *value = v & ((1u<<value_bits)-1);
104
259M
    return true;
105
303M
  }
Unexecuted instantiation: hb_cache_t<24u, 16u, 8u, true>::get(unsigned int, unsigned int*) const
hb_cache_t<20u, 20u, 8u, true>::get(unsigned int, unsigned int*) const
Line
Count
Source
94
652k
  {
95
652k
    unsigned int k = key & ((1u<<cache_bits)-1);
96
652k
    unsigned int v = values[k];
97
652k
    constexpr unsigned int empty = (1ULL << (8 * sizeof (item_t))) - 1;
98
    /* Combine overflow, tag mismatch, and empty checks into one branch. */
99
652k
    if ((key >> key_bits) |
100
652k
  ((v >> value_bits) ^ (key >> cache_bits)) |
101
652k
  ((key_bits + value_bits - cache_bits == 8 * sizeof (item_t)) && (v == empty)))
102
598
      return false;
103
652k
    *value = v & ((1u<<value_bits)-1);
104
652k
    return true;
105
652k
  }
106
107
  HB_HOT
108
  void set (unsigned int key, unsigned int value)
109
2.89M
  {
110
2.89M
    if (unlikely ((key >> key_bits) || (value >> value_bits)))
111
575k
      return; /* Overflows */
112
2.31M
    unsigned int k = key & ((1u<<cache_bits)-1);
113
2.31M
    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
114
2.31M
    values[k] = v;
115
2.31M
  }
hb_cache_t<16u, 8u, 8u, true>::set(unsigned int, unsigned int)
Line
Count
Source
109
190k
  {
110
190k
    if (unlikely ((key >> key_bits) || (value >> value_bits)))
111
0
      return; /* Overflows */
112
190k
    unsigned int k = key & ((1u<<cache_bits)-1);
113
190k
    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
114
190k
    values[k] = v;
115
190k
  }
hb_cache_t<21u, 3u, 8u, true>::set(unsigned int, unsigned int)
Line
Count
Source
109
1.56M
  {
110
1.56M
    if (unlikely ((key >> key_bits) || (value >> value_bits)))
111
567k
      return; /* Overflows */
112
999k
    unsigned int k = key & ((1u<<cache_bits)-1);
113
999k
    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
114
999k
    values[k] = v;
115
999k
  }
hb_cache_t<14u, 1u, 8u, true>::set(unsigned int, unsigned int)
Line
Count
Source
109
15.5k
  {
110
15.5k
    if (unlikely ((key >> key_bits) || (value >> value_bits)))
111
7.42k
      return; /* Overflows */
112
8.14k
    unsigned int k = key & ((1u<<cache_bits)-1);
113
8.14k
    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
114
8.14k
    values[k] = v;
115
8.14k
  }
hb_cache_t<21u, 19u, 8u, true>::set(unsigned int, unsigned int)
Line
Count
Source
109
1.12M
  {
110
1.12M
    if (unlikely ((key >> key_bits) || (value >> value_bits)))
111
1.00k
      return; /* Overflows */
112
1.12M
    unsigned int k = key & ((1u<<cache_bits)-1);
113
1.12M
    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
114
1.12M
    values[k] = v;
115
1.12M
  }
Unexecuted instantiation: hb_cache_t<24u, 16u, 8u, true>::set(unsigned int, unsigned int)
hb_cache_t<20u, 20u, 8u, true>::set(unsigned int, unsigned int)
Line
Count
Source
109
598
  {
110
598
    if (unlikely ((key >> key_bits) || (value >> value_bits)))
111
0
      return; /* Overflows */
112
598
    unsigned int k = key & ((1u<<cache_bits)-1);
113
598
    unsigned int v = ((key>>cache_bits)<<value_bits) | value;
114
598
    values[k] = v;
115
598
  }
116
117
  private:
118
  item_t values[1u<<cache_bits];
119
};
120
121
122
#endif /* HB_CACHE_HH */