| /* | |
| * This is part of HarfBuzz, a text shaping library. | |
| * | |
| * Permission is hereby granted, without written agreement and without | |
| * license or royalty fees, to use, copy, modify, and distribute this | |
| * software and its documentation for any purpose, provided that the | |
| * above copyright notice and the following two paragraphs appear in | |
| * all copies of this software. | |
| * | |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
| * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
| * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
| * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
| * DAMAGE. | |
| * | |
| * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
| * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
| * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
| * | |
| * Author(s): Behdad Esfahbod | |
| */ | |
| #ifndef HB_BIT_VECTOR_HH | |
| #define HB_BIT_VECTOR_HH | |
| #include "hb.hh" | |
| #include "hb-atomic.hh" | |
| struct hb_min_max_t | |
| { | |
| void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); } | |
| void add_range (hb_codepoint_t a, hb_codepoint_t b) | |
| { | |
| min_v = hb_min (min_v, a); | |
| max_v = hb_max (max_v, b); | |
| } | |
| template <typename set_t> | |
| void union_ (const set_t &set) | |
| { | |
| hb_codepoint_t set_min = set.get_min (); | |
| if (unlikely (set_min == HB_CODEPOINT_INVALID)) | |
| return; | |
| hb_codepoint_t set_max = set.get_max (); | |
| min_v = hb_min (min_v, set_min); | |
| max_v = hb_max (max_v, set_max); | |
| } | |
| hb_codepoint_t get_min () const { return min_v; } | |
| hb_codepoint_t get_max () const { return max_v; } | |
| private: | |
| hb_codepoint_t min_v = HB_CODEPOINT_INVALID; | |
| hb_codepoint_t max_v = 0; | |
| }; | |
| template <bool atomic = false> | |
| struct hb_bit_vector_t | |
| { | |
| using int_t = uint64_t; | |
| using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type; | |
| hb_bit_vector_t () = delete; | |
| hb_bit_vector_t (const hb_bit_vector_t &other) = delete; | |
| hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete; | |
| // Move | |
| hb_bit_vector_t (hb_bit_vector_t &&other) | |
| : min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts) | |
| { | |
| other.min_v = other.max_v = other.count = 0; | |
| other.elts = nullptr; | |
| } | |
| hb_bit_vector_t &operator= (hb_bit_vector_t &&other) | |
| { | |
| hb_swap (min_v, other.min_v); | |
| hb_swap (max_v, other.max_v); | |
| hb_swap (count, other.count); | |
| hb_swap (elts, other.elts); | |
| return *this; | |
| } | |
| hb_bit_vector_t (unsigned min_v, unsigned max_v) | |
| : min_v (min_v), max_v (max_v) | |
| { | |
| if (unlikely (min_v >= max_v)) | |
| { | |
| min_v = max_v = count = 0; | |
| return; | |
| } | |
| unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8); | |
| elts = (elt_t *) hb_calloc (num, sizeof (int_t)); | |
| if (unlikely (!elts)) | |
| { | |
| min_v = max_v = count = 0; | |
| return; | |
| } | |
| count = max_v - min_v + 1; | |
| } | |
| ~hb_bit_vector_t () | |
| { | |
| hb_free (elts); | |
| } | |
| void add (hb_codepoint_t g) { elt (g) |= mask (g); } | |
| void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } | |
| void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } | |
| bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } | |
| bool has (hb_codepoint_t g) const { return get (g); } | |
| bool may_have (hb_codepoint_t g) const { return get (g); } | |
| bool operator [] (hb_codepoint_t g) const { return get (g); } | |
| bool operator () (hb_codepoint_t g) const { return get (g); } | |
| void add_range (hb_codepoint_t a, hb_codepoint_t b) | |
| { | |
| if (unlikely (!count || a > b || a < min_v || b > max_v)) | |
| return; | |
| elt_t *la = &elt (a); | |
| elt_t *lb = &elt (b); | |
| if (la == lb) | |
| *la |= (mask (b) << 1) - mask(a); | |
| else | |
| { | |
| *la |= ~(mask (a) - 1llu); | |
| la++; | |
| hb_memset (la, 0xff, (char *) lb - (char *) la); | |
| *lb |= ((mask (b) << 1) - 1llu); | |
| } | |
| } | |
| void del_range (hb_codepoint_t a, hb_codepoint_t b) | |
| { | |
| if (unlikely (!count || a > b || a < min_v || b > max_v)) | |
| return; | |
| elt_t *la = &elt (a); | |
| elt_t *lb = &elt (b); | |
| if (la == lb) | |
| *la &= ~((mask (b) << 1llu) - mask(a)); | |
| else | |
| { | |
| *la &= mask (a) - 1; | |
| la++; | |
| hb_memset (la, 0, (char *) lb - (char *) la); | |
| *lb &= ~((mask (b) << 1) - 1llu); | |
| } | |
| } | |
| void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v) | |
| { if (v) add_range (a, b); else del_range (a, b); } | |
| template <typename set_t> | |
| void union_ (const set_t &set) | |
| { | |
| for (hb_codepoint_t g : set) | |
| add (g); | |
| } | |
| static const unsigned int ELT_BITS = sizeof (elt_t) * 8; | |
| static constexpr unsigned ELT_MASK = ELT_BITS - 1; | |
| static constexpr elt_t zero = 0; | |
| elt_t &elt (hb_codepoint_t g) | |
| { | |
| g -= min_v; | |
| if (unlikely (g >= count)) | |
| return Crap(elt_t); | |
| return elts[g / ELT_BITS]; | |
| } | |
| const elt_t& elt (hb_codepoint_t g) const | |
| { | |
| g -= min_v; | |
| if (unlikely (g >= count)) | |
| return Null(elt_t); | |
| return elts[g / ELT_BITS]; | |
| } | |
| static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); } | |
| hb_codepoint_t min_v = 0, max_v = 0, count = 0; | |
| elt_t *elts = nullptr; | |
| }; | |
| #endif /* HB_BIT_VECTOR_HH */ |