[set] Add backwards iterator
New API: - hb_set_previous() - hb_set_previous_range()
This commit is contained in:
parent
fe3bc524bd
commit
694eaf6367
@ -528,7 +528,9 @@ hb_set_intersect
|
|||||||
hb_set_is_empty
|
hb_set_is_empty
|
||||||
hb_set_is_equal
|
hb_set_is_equal
|
||||||
hb_set_next
|
hb_set_next
|
||||||
|
hb_set_previous
|
||||||
hb_set_next_range
|
hb_set_next_range
|
||||||
|
hb_set_previous_range
|
||||||
hb_set_reference
|
hb_set_reference
|
||||||
hb_set_set
|
hb_set_set
|
||||||
hb_set_set_user_data
|
hb_set_set_user_data
|
||||||
|
@ -121,6 +121,33 @@ struct hb_set_t
|
|||||||
*codepoint = INVALID;
|
*codepoint = INVALID;
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
found:
|
||||||
|
*codepoint = i * ELT_BITS + j;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
inline bool previous (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
unsigned int m = (*codepoint - 1) & MASK;
|
||||||
|
if (m == MASK)
|
||||||
|
{
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
unsigned int i = m / ELT_BITS;
|
||||||
|
unsigned int j = m & ELT_MASK;
|
||||||
|
|
||||||
|
for (; (int) j >= 0; j--)
|
||||||
|
if (v[i] & (elt_t (1) << j))
|
||||||
|
goto found;
|
||||||
|
for (i--; (int) i >= 0; i--)
|
||||||
|
if (v[i])
|
||||||
|
for (j = ELT_BITS - 1; (int) j >= 0; j--)
|
||||||
|
if (v[i] & (elt_t (1) << j))
|
||||||
|
goto found;
|
||||||
|
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
*codepoint = i * ELT_BITS + j;
|
*codepoint = i * ELT_BITS + j;
|
||||||
return true;
|
return true;
|
||||||
@ -476,7 +503,7 @@ struct hb_set_t
|
|||||||
if (pages[page_map[i].index].next (codepoint))
|
if (pages[page_map[i].index].next (codepoint))
|
||||||
{
|
{
|
||||||
*codepoint += page_map[i].major * page_t::PAGE_BITS;
|
*codepoint += page_map[i].major * page_t::PAGE_BITS;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -492,6 +519,37 @@ struct hb_set_t
|
|||||||
*codepoint = INVALID;
|
*codepoint = INVALID;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
inline bool previous (hb_codepoint_t *codepoint) const
|
||||||
|
{
|
||||||
|
if (unlikely (*codepoint == INVALID)) {
|
||||||
|
*codepoint = get_max ();
|
||||||
|
return *codepoint != INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
page_map_t map = {get_major (*codepoint), 0};
|
||||||
|
unsigned int i;
|
||||||
|
page_map.bfind (map, &i);
|
||||||
|
if (i < page_map.len && page_map[i].major == map.major)
|
||||||
|
{
|
||||||
|
if (pages[page_map[i].index].previous (codepoint))
|
||||||
|
{
|
||||||
|
*codepoint += page_map[i].major * page_t::PAGE_BITS;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
for (; (int) i >= 0; i--)
|
||||||
|
{
|
||||||
|
hb_codepoint_t m = pages[page_map[i].index].get_max ();
|
||||||
|
if (m != INVALID)
|
||||||
|
{
|
||||||
|
*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*codepoint = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
{
|
{
|
||||||
hb_codepoint_t i;
|
hb_codepoint_t i;
|
||||||
@ -503,12 +561,31 @@ struct hb_set_t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO Speed up. */
|
||||||
*last = *first = i;
|
*last = *first = i;
|
||||||
while (next (&i) && i == *last + 1)
|
while (next (&i) && i == *last + 1)
|
||||||
(*last)++;
|
(*last)++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
inline bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
|
||||||
|
{
|
||||||
|
hb_codepoint_t i;
|
||||||
|
|
||||||
|
i = *first;
|
||||||
|
if (!previous (&i))
|
||||||
|
{
|
||||||
|
*last = *first = INVALID;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO Speed up. */
|
||||||
|
*last = *first = i;
|
||||||
|
while (previous (&i) && i == *first - 1)
|
||||||
|
(*first)--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline unsigned int get_population (void) const
|
inline unsigned int get_population (void) const
|
||||||
{
|
{
|
||||||
|
@ -437,7 +437,9 @@ hb_set_get_max (const hb_set_t *set)
|
|||||||
* @set: a set.
|
* @set: a set.
|
||||||
* @codepoint: (inout):
|
* @codepoint: (inout):
|
||||||
*
|
*
|
||||||
*
|
* Gets the next number in @set that is greater than current value of @codepoint.
|
||||||
|
*
|
||||||
|
* Set @codepoint to %HB_SET_VALUE_INVALID to get started.
|
||||||
*
|
*
|
||||||
* Return value: whether there was a next value.
|
* Return value: whether there was a next value.
|
||||||
*
|
*
|
||||||
@ -450,6 +452,26 @@ hb_set_next (const hb_set_t *set,
|
|||||||
return set->next (codepoint);
|
return set->next (codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_set_previous:
|
||||||
|
* @set: a set.
|
||||||
|
* @codepoint: (inout):
|
||||||
|
*
|
||||||
|
* Gets the previous number in @set that is slower than current value of @codepoint.
|
||||||
|
*
|
||||||
|
* Set @codepoint to %HB_SET_VALUE_INVALID to get started.
|
||||||
|
*
|
||||||
|
* Return value: whether there was a previous value.
|
||||||
|
*
|
||||||
|
* Since: 1.8.0
|
||||||
|
**/
|
||||||
|
hb_bool_t
|
||||||
|
hb_set_previous (const hb_set_t *set,
|
||||||
|
hb_codepoint_t *codepoint)
|
||||||
|
{
|
||||||
|
return set->previous (codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hb_set_next_range:
|
* hb_set_next_range:
|
||||||
* @set: a set.
|
* @set: a set.
|
||||||
@ -459,6 +481,8 @@ hb_set_next (const hb_set_t *set,
|
|||||||
* Gets the next consecutive range of numbers in @set that
|
* Gets the next consecutive range of numbers in @set that
|
||||||
* are greater than current value of @last.
|
* are greater than current value of @last.
|
||||||
*
|
*
|
||||||
|
* Set @last to %HB_SET_VALUE_INVALID to get started.
|
||||||
|
*
|
||||||
* Return value: whether there was a next range.
|
* Return value: whether there was a next range.
|
||||||
*
|
*
|
||||||
* Since: 0.9.7
|
* Since: 0.9.7
|
||||||
@ -470,3 +494,26 @@ hb_set_next_range (const hb_set_t *set,
|
|||||||
{
|
{
|
||||||
return set->next_range (first, last);
|
return set->next_range (first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_set_previous_range:
|
||||||
|
* @set: a set.
|
||||||
|
* @first: (inout): input current first and output first codepoint in the range.
|
||||||
|
* @last: (out): output last codepoint in the range.
|
||||||
|
*
|
||||||
|
* Gets the previous consecutive range of numbers in @set that
|
||||||
|
* are greater than current value of @last.
|
||||||
|
*
|
||||||
|
* Set @first to %HB_SET_VALUE_INVALID to get started.
|
||||||
|
*
|
||||||
|
* Return value: whether there was a previous range.
|
||||||
|
*
|
||||||
|
* Since: 1.8.0
|
||||||
|
**/
|
||||||
|
hb_bool_t
|
||||||
|
hb_set_previous_range (const hb_set_t *set,
|
||||||
|
hb_codepoint_t *first,
|
||||||
|
hb_codepoint_t *last)
|
||||||
|
{
|
||||||
|
return set->previous_range (first, last);
|
||||||
|
}
|
||||||
|
19
src/hb-set.h
19
src/hb-set.h
@ -129,25 +129,36 @@ hb_set_symmetric_difference (hb_set_t *set,
|
|||||||
HB_EXTERN unsigned int
|
HB_EXTERN unsigned int
|
||||||
hb_set_get_population (const hb_set_t *set);
|
hb_set_get_population (const hb_set_t *set);
|
||||||
|
|
||||||
/* Returns -1 if set empty. */
|
/* Returns HB_SET_VALUE_INVALID if set empty. */
|
||||||
HB_EXTERN hb_codepoint_t
|
HB_EXTERN hb_codepoint_t
|
||||||
hb_set_get_min (const hb_set_t *set);
|
hb_set_get_min (const hb_set_t *set);
|
||||||
|
|
||||||
/* Returns -1 if set empty. */
|
/* Returns HB_SET_VALUE_INVALID if set empty. */
|
||||||
HB_EXTERN hb_codepoint_t
|
HB_EXTERN hb_codepoint_t
|
||||||
hb_set_get_max (const hb_set_t *set);
|
hb_set_get_max (const hb_set_t *set);
|
||||||
|
|
||||||
/* Pass -1 in to get started. */
|
/* Pass HB_SET_VALUE_INVALID in to get started. */
|
||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_set_next (const hb_set_t *set,
|
hb_set_next (const hb_set_t *set,
|
||||||
hb_codepoint_t *codepoint);
|
hb_codepoint_t *codepoint);
|
||||||
|
|
||||||
/* Pass -1 for first and last to get started. */
|
/* Pass HB_SET_VALUE_INVALID in to get started. */
|
||||||
|
HB_EXTERN hb_bool_t
|
||||||
|
hb_set_previous (const hb_set_t *set,
|
||||||
|
hb_codepoint_t *codepoint);
|
||||||
|
|
||||||
|
/* Pass HB_SET_VALUE_INVALID for first and last to get started. */
|
||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_set_next_range (const hb_set_t *set,
|
hb_set_next_range (const hb_set_t *set,
|
||||||
hb_codepoint_t *first,
|
hb_codepoint_t *first,
|
||||||
hb_codepoint_t *last);
|
hb_codepoint_t *last);
|
||||||
|
|
||||||
|
/* Pass HB_SET_VALUE_INVALID for first and last to get started. */
|
||||||
|
HB_EXTERN hb_bool_t
|
||||||
|
hb_set_previous_range (const hb_set_t *set,
|
||||||
|
hb_codepoint_t *first,
|
||||||
|
hb_codepoint_t *last);
|
||||||
|
|
||||||
|
|
||||||
HB_END_DECLS
|
HB_END_DECLS
|
||||||
|
|
||||||
|
@ -32,25 +32,33 @@
|
|||||||
static void
|
static void
|
||||||
test_empty (hb_set_t *s)
|
test_empty (hb_set_t *s)
|
||||||
{
|
{
|
||||||
hb_codepoint_t next = HB_SET_VALUE_INVALID;
|
hb_codepoint_t next;
|
||||||
g_assert_cmpint (hb_set_get_population (s), ==, 0);
|
g_assert_cmpint (hb_set_get_population (s), ==, 0);
|
||||||
g_assert_cmpint (hb_set_get_min (s), ==, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (hb_set_get_min (s), ==, HB_SET_VALUE_INVALID);
|
||||||
g_assert_cmpint (hb_set_get_max (s), ==, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (hb_set_get_max (s), ==, HB_SET_VALUE_INVALID);
|
||||||
g_assert (!hb_set_has (s, 13));
|
g_assert (!hb_set_has (s, 13));
|
||||||
|
next = 53043;
|
||||||
g_assert (!hb_set_next (s, &next));
|
g_assert (!hb_set_next (s, &next));
|
||||||
g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
|
||||||
|
next = 07734;
|
||||||
|
g_assert (!hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
|
||||||
g_assert (hb_set_is_empty (s));
|
g_assert (hb_set_is_empty (s));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_not_empty (hb_set_t *s)
|
test_not_empty (hb_set_t *s)
|
||||||
{
|
{
|
||||||
hb_codepoint_t next = HB_SET_VALUE_INVALID;
|
hb_codepoint_t next;
|
||||||
g_assert_cmpint (hb_set_get_population (s), !=, 0);
|
g_assert_cmpint (hb_set_get_population (s), !=, 0);
|
||||||
g_assert_cmpint (hb_set_get_min (s), !=, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (hb_set_get_min (s), !=, HB_SET_VALUE_INVALID);
|
||||||
g_assert_cmpint (hb_set_get_max (s), !=, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (hb_set_get_max (s), !=, HB_SET_VALUE_INVALID);
|
||||||
|
next = HB_SET_VALUE_INVALID;
|
||||||
g_assert (hb_set_next (s, &next));
|
g_assert (hb_set_next (s, &next));
|
||||||
g_assert_cmpint (next, !=, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (next, !=, HB_SET_VALUE_INVALID);
|
||||||
|
next = HB_SET_VALUE_INVALID;
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, !=, HB_SET_VALUE_INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -271,6 +279,27 @@ test_set_iter (void)
|
|||||||
g_assert (!hb_set_next (s, &next));
|
g_assert (!hb_set_next (s, &next));
|
||||||
g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
|
||||||
|
|
||||||
|
next = HB_SET_VALUE_INVALID;
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 20005);
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 1200);
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 1100);
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 15);
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 13);
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 10);
|
||||||
|
g_assert (hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, 6);
|
||||||
|
g_assert (!hb_set_previous (s, &next));
|
||||||
|
g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
|
||||||
|
|
||||||
first = last = HB_SET_VALUE_INVALID;
|
first = last = HB_SET_VALUE_INVALID;
|
||||||
g_assert (hb_set_next_range (s, &first, &last));
|
g_assert (hb_set_next_range (s, &first, &last));
|
||||||
g_assert_cmpint (first, ==, 6);
|
g_assert_cmpint (first, ==, 6);
|
||||||
@ -291,6 +320,26 @@ test_set_iter (void)
|
|||||||
g_assert_cmpint (first, ==, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (first, ==, HB_SET_VALUE_INVALID);
|
||||||
g_assert_cmpint (last, ==, HB_SET_VALUE_INVALID);
|
g_assert_cmpint (last, ==, HB_SET_VALUE_INVALID);
|
||||||
|
|
||||||
|
first = last = HB_SET_VALUE_INVALID;
|
||||||
|
g_assert (hb_set_previous_range (s, &first, &last));
|
||||||
|
g_assert_cmpint (first, ==, 20005);
|
||||||
|
g_assert_cmpint (last, ==, 20005);
|
||||||
|
g_assert (hb_set_previous_range (s, &first, &last));
|
||||||
|
g_assert_cmpint (first, ==, 1200);
|
||||||
|
g_assert_cmpint (last, ==, 1200);
|
||||||
|
g_assert (hb_set_previous_range (s, &first, &last));
|
||||||
|
g_assert_cmpint (first, ==, 1100);
|
||||||
|
g_assert_cmpint (last, ==, 1100);
|
||||||
|
g_assert (hb_set_previous_range (s, &first, &last));
|
||||||
|
g_assert_cmpint (first, ==, 10);
|
||||||
|
g_assert_cmpint (last, ==, 15);
|
||||||
|
g_assert (hb_set_previous_range (s, &first, &last));
|
||||||
|
g_assert_cmpint (first, ==, 6);
|
||||||
|
g_assert_cmpint (last, ==, 6);
|
||||||
|
g_assert (!hb_set_previous_range (s, &first, &last));
|
||||||
|
g_assert_cmpint (first, ==, HB_SET_VALUE_INVALID);
|
||||||
|
g_assert_cmpint (last, ==, HB_SET_VALUE_INVALID);
|
||||||
|
|
||||||
hb_set_destroy (s);
|
hb_set_destroy (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user