diff --git a/docs/reference/gtk/gtk4-docs.xml b/docs/reference/gtk/gtk4-docs.xml index 4c57d0c60a..2351a3688b 100644 --- a/docs/reference/gtk/gtk4-docs.xml +++ b/docs/reference/gtk/gtk4-docs.xml @@ -48,6 +48,7 @@ GListModel support +
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 39e04bfb81..447e1c0d6c 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -339,6 +339,51 @@ gtk_list_box_get_type gtk_list_box_row_get_type
+
+gtkbitset +GtkBitset +GtkBitset +gtk_bitset_ref +gtk_bitset_unref +gtk_bitset_new_empty +gtk_bitset_copy + +gtk_bitset_contains +gtk_bitset_is_empty +gtk_bitset_equals +gtk_bitset_get_minimum +gtk_bitset_get_maximum + +gtk_bitset_remove_all +gtk_bitset_add +gtk_bitset_remove +gtk_bitset_add_range +gtk_bitset_remove_range +gtk_bitset_add_range_closed +gtk_bitset_remove_range_closed +gtk_bitset_add_rectangle +gtk_bitset_remove_rectangle +gtk_bitset_union +gtk_bitset_intersect +gtk_bitset_subtract +gtk_bitset_difference +gtk_bitset_shift_left +gtk_bitset_shift_right +gtk_bitset_slice + +GtkBitsetIter +gtk_bitset_iter_init_first +gtk_bitset_iter_init_last +gtk_bitset_iter_init_at +gtk_bitset_iter_next +gtk_bitset_iter_previous +gtk_bitset_iter_get_value +gtk_bitset_iter_is_valid + +GTK_TYPE_BITSET +gtk_bitset_get_type +
+
gtkselectionmodel GtkSelectionModel diff --git a/docs/reference/gtk/gtk4.types.in b/docs/reference/gtk/gtk4.types.in index ac13151dca..9090e496c8 100644 --- a/docs/reference/gtk/gtk4.types.in +++ b/docs/reference/gtk/gtk4.types.in @@ -18,6 +18,7 @@ gtk_aspect_frame_get_type gtk_assistant_get_type gtk_assistant_page_get_type gtk_bin_layout_get_type +gtk_bitset_get_type gtk_bookmark_list_get_type gtk_box_get_type gtk_box_layout_get_type diff --git a/gtk/gtk.h b/gtk/gtk.h index 0ab53bfd33..0aa7ad888e 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkbitset.c b/gtk/gtkbitset.c new file mode 100644 index 0000000000..b9bde5b90b --- /dev/null +++ b/gtk/gtkbitset.c @@ -0,0 +1,865 @@ +/* + * Copyright © 2020 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gtkbitset.h" + +#include "roaring.c" + +/** + * SECTION:gtkbitset + * @Short_description: Sets of integers + * @Title: GtkBitset + * @See_also: GtkSelectionModel + * + * #GtkBitset is a data structure for representing a set of unsigned integers. + * Another name for this data structure is "bitmap". + * + * This version is based on [roaring bitmaps](https://roaringbitmap.org/). + * + * A bitset allows adding a set of integers and provides support for set operations + * like unions, intersections and checks for equality or if a value is contained + * in the set. #GtkBitset also contains various functions to query metadata about + * the bitset, such as the minimum or maximum values or its size. + * + * The fastest way to iterate values in a bitset is #GtkBitsetIter which allows + * quick iteration of all the values in a bitset. + * + * The main use case #GtkBitset is implementing complex selections for #GtkSelectionModel. + */ + +/** + * GtkBitset: (ref-func gtk_bitset_ref) (unref-func gtk_bitset_unref) + * + * The `GtkBitset` structure contains only private data. + */ +struct _GtkBitset +{ + int ref_count; + roaring_bitmap_t roaring; +}; + + +G_DEFINE_BOXED_TYPE (GtkBitset, gtk_bitset, + gtk_bitset_ref, + gtk_bitset_unref) + +/** + * gtk_bitset_ref: + * @self: (allow-none): a #GtkBitset + * + * Acquires a reference on the given #GtkBitset. + * + * Returns: (transfer none): the #GtkBitset with an additional reference + */ +GtkBitset * +gtk_bitset_ref (GtkBitset *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + self->ref_count += 1; + + return self; +} + +/** + * gtk_bitset_unref: + * @self: (allow-none): a #GtkBitset + * + * Releases a reference on the given #GtkBitset. + * + * If the reference was the last, the resources associated to the @self are + * freed. + */ +void +gtk_bitset_unref (GtkBitset *self) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (self->ref_count > 0); + + self->ref_count -= 1; + if (self->ref_count > 0) + return; + + ra_clear (&self->roaring.high_low_container); + g_slice_free (GtkBitset, self); +} + +/** + * gtk_bitset_contains: + * @self: a #GtkBitset + * @value: the value to check + * + * Checks if the given @value has been added to @bitset + * + * Returns: %TRUE if @self contains @value + **/ +gboolean +gtk_bitset_contains (const GtkBitset *self, + guint value) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return roaring_bitmap_contains (&self->roaring, value); +} + +/** + * gtk_bitset_is_empty: + * @self: a #GtkBitset + * + * Check if no value is contained in bitset. + * + * Returns: %TRUE if @self is empty + **/ +gboolean +gtk_bitset_is_empty (const GtkBitset *self) +{ + g_return_val_if_fail (self != NULL, TRUE); + + return roaring_bitmap_is_empty (&self->roaring); +} + +/** + * gtk_bitset_equals: + * @self: a #GtkBitset + * @other: another #GtkBitset + * + * Returns %TRUE if @self and @other contain the same values. + * + * Returns: %TRUE if @self and @other contain the same values + **/ +gboolean +gtk_bitset_equals (const GtkBitset *self, + const GtkBitset *other) +{ + g_return_val_if_fail (self != NULL, other == NULL); + g_return_val_if_fail (other != NULL, FALSE); + + if (self == other) + return TRUE; + + return roaring_bitmap_equals (&self->roaring, &other->roaring); +} + +/** + * gtk_bitset_get_minimum: + * @self: a #GtkBitset + * + * Returns the smallest value in @self. If @self is empty, + * G_MAXUINT is returned. + * + * Returns: The smallest value in @self + **/ +guint +gtk_bitset_get_minimum (const GtkBitset *self) +{ + g_return_val_if_fail (self != NULL, G_MAXUINT); + + return roaring_bitmap_minimum (&self->roaring); +} + +/** + * gtk_bitset_get_maximum: + * @self: a #GtkBitset + * + * Returns the largest value in @self. If @self is empty, + * 0 is returned. + * + * Returns: The largest value in @self + **/ +guint +gtk_bitset_get_maximum (const GtkBitset *self) +{ + g_return_val_if_fail (self != NULL, 0); + + return roaring_bitmap_maximum (&self->roaring); +} + +/** + * gtk_bitset_new_empty: + * + * Creates a new empty bitset. + * + * Returns: A new empty bitset. + **/ +GtkBitset * +gtk_bitset_new_empty (void) +{ + GtkBitset *self; + + self = g_slice_new0 (GtkBitset); + + self->ref_count = 1; + + ra_init (&self->roaring.high_low_container); + + return self; +} + +/** + * gtk_bitset_copy: + * @self: a #GtkBitset + * + * Creates a copy of @self. + * + * Returns: (transfer full) A new bitset that contains the same + * values as @self + **/ +GtkBitset * +gtk_bitset_copy (const GtkBitset *self) +{ + GtkBitset *copy; + + g_return_val_if_fail (self != NULL, NULL); + + copy = gtk_bitset_new_empty (); + roaring_bitmap_overwrite (©->roaring, &self->roaring); + + return copy; +} + +/** + * gtk_bitset_remove_all: + * @self: a #GtkBitset + * + * Removes all values from the bitset so that it is empty again. + **/ +void +gtk_bitset_remove_all (GtkBitset *self) +{ + g_return_if_fail (self != NULL); + + roaring_bitmap_clear (&self->roaring); +} + +/** + * gtk_bitset_add: + * @self: a #GtkBitset + * @value: value to add + * + * Adds @value to @self if it wasn't part of it before. + * + * Returns: %TRUE if @value was not part of @self and @self + * was changed. + **/ +gboolean +gtk_bitset_add (GtkBitset *self, + guint value) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return roaring_bitmap_add_checked (&self->roaring, value); +} + +/** + * gtk_bitset_remove: + * @self: a #GtkBitset + * @value: value to add + * + * Adds @value to @self if it wasn't part of it before. + * + * Returns: %TRUE if @value was part of @self and @self + * was changed. + **/ +gboolean +gtk_bitset_remove (GtkBitset *self, + guint value) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return roaring_bitmap_remove_checked (&self->roaring, value); +} + +/** + * gtk_bitset_add_range: + * @self: a #GtkBitset + * @start: first value to add + * @n_items: number of consecutive values to add + * + * Adds all values from @start (inclusive) to @start + @n_items (exclusive) + * in @self. + **/ +void +gtk_bitset_add_range (GtkBitset *self, + guint start, + guint n_items) +{ + g_return_if_fail (self != NULL); + + if (n_items == 0) + return; + + /* overflow check, the == 0 is to allow add_range(G_MAXUINT, 1); */ + g_return_if_fail (start + n_items == 0 || start + n_items > start); + + roaring_bitmap_add_range_closed (&self->roaring, start, start + n_items - 1); +} + +/** + * gtk_bitset_remove_range: + * @self: a #GtkBitset + * @start: first value to remove + * @n_items: number of consecutive values to remove + * + * Removes all values from @start (inclusive) to @start + @n_items (exclusive) + * in @self. + **/ +void +gtk_bitset_remove_range (GtkBitset *self, + guint start, + guint n_items) +{ + g_return_if_fail (self != NULL); + + if (n_items == 0) + return; + + /* overflow check, the == 0 is to allow add_range(G_MAXUINT, 1); */ + g_return_if_fail (start + n_items == 0 || start + n_items > start); + + roaring_bitmap_remove_range_closed (&self->roaring, start, start + n_items - 1); +} + +/** + * gtk_bitset_add_range_closed: + * @self: a #GtkBitset + * @first: first value to add + * @last: last value to add + * + * Adds the closed range [@first, @last], so @first, @last and all values inbetween. + * @first must be smaller than @last. + **/ +void +gtk_bitset_add_range_closed (GtkBitset *self, + guint first, + guint last) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (first <= last); + + roaring_bitmap_add_range_closed (&self->roaring, first, last); +} + +/** + * gtk_bitset_remove_range_closed: + * @self: a #GtkBitset + * @first: first value to remove + * @last: last value to remove + * + * Removes the closed range [@first, @last], so @first, @last and all values inbetween. + * @first must be smaller than @last. + **/ +void +gtk_bitset_remove_range_closed (GtkBitset *self, + guint first, + guint last) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (first <= last); + + roaring_bitmap_remove_range_closed (&self->roaring, first, last); +} + +/** + * gtk_bitset_add_rectangle: + * @self: a #GtkBitset + * @start: first value to add + * @width: width of the rectangle + * @height: height of the rectangle + * @stride: rowstride of the rectangle + * + * Interprets the values as a 2-dimensional boolean grid with the given @stride + * and inside that grid, adds a rectangle with the given @width and @height. + **/ +void +gtk_bitset_add_rectangle (GtkBitset *self, + guint start, + guint width, + guint height, + guint stride) +{ + guint i; + + g_return_if_fail (self != NULL); + g_return_if_fail (width <= stride); + g_return_if_fail (G_MAXUINT - start >= height * stride); + + if (width == 0 || height == 0) + return; + + for (i = 0; i < height; i++) + gtk_bitset_add_range (self, i * stride + start, width); +} + +/** + * gtk_bitset_remove_rectangle: + * @self: a #GtkBitset + * @start: first value to remove + * @width: width of the rectangle + * @height: height of the rectangle + * @stride: rowstride of the rectangle + * + * Interprets the values as a 2-dimensional boolean grid with the given @stride + * and inside that grid, removes a rectangle with the given @width and @height. + **/ +void +gtk_bitset_remove_rectangle (GtkBitset *self, + guint start, + guint width, + guint height, + guint stride) +{ + guint i; + + g_return_if_fail (self != NULL); + g_return_if_fail (width <= stride); + g_return_if_fail (G_MAXUINT - start >= height * stride); + + if (width == 0 || height == 0) + return; + + for (i = 0; i < height; i++) + gtk_bitset_remove_range (self, i * stride + start, width); +} + +/** + * gtk_bitset_union: + * @self: a #GtkBitset + * @other: the #GtkBitset to union with + * + * Sets @self to be the union of @self and @other, that is add all values + * from @other into @self that weren't part of it. + * + * It is allowed for @self and @other to be the same bitset. Nothing will + * happen in that case. + **/ +void +gtk_bitset_union (GtkBitset *self, + const GtkBitset *other) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (other != NULL); + + if (self == other) + return; + + roaring_bitmap_or_inplace (&self->roaring, &other->roaring); +} + +/** + * gtk_bitset_intersect: + * @self: a #GtkBitset + * @other: the #GtkBitset to intersect with + * + * Sets @self to be the intersection of @self and @other, that is remove all values + * from @self that are not part of @other. + * + * It is allowed for @self and @other to be the same bitset. Nothing will + * happen in that case. + **/ +void +gtk_bitset_intersect (GtkBitset *self, + const GtkBitset *other) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (other != NULL); + + if (self == other) + return; + + roaring_bitmap_and_inplace (&self->roaring, &other->roaring); +} + +/** + * gtk_bitset_subtract: + * @self: a #GtkBitset + * @other: the #GtkBitset to subtract + * + * Sets @self to be the subtraction of @other from @self, that is remove + * all values from @self that are part of @other. + * + * It is allowed for @self and @other to be the same bitset. The bitset + * will be emptied in that case. + **/ +void +gtk_bitset_subtract (GtkBitset *self, + const GtkBitset *other) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (other != NULL); + + if (self == other) + { + roaring_bitmap_clear (&self->roaring); + return; + } + + roaring_bitmap_andnot_inplace (&self->roaring, &other->roaring); +} + +/** + * gtk_bitset_difference: + * @self: a #GtkBitset + * @other: the #GtkBitset to compute the difference from + * + * Sets @self to be the symmetric difference of @self and @other, that + * is set @self to contain all values that were either contained in @self + * or in @other, but not in both. + * This operation is also called an XOR. + * + * It is allowed for @self and @other to be the same bitset. The bitset + * will be emptied in that case. + **/ +void +gtk_bitset_difference (GtkBitset *self, + const GtkBitset *other) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (other != NULL); + + if (self == other) + { + roaring_bitmap_clear (&self->roaring); + return; + } + + roaring_bitmap_xor_inplace (&self->roaring, &other->roaring); +} + +/** + * gtk_bitset_shift_left: + * @self: a $GtkBitset + * @amount: amount to shift all values to the left + * + * Shifts all values in @self to the left by @amount. Values + * smaller than @amount are discarded. + **/ +void +gtk_bitset_shift_left (GtkBitset *self, + guint amount) +{ + GtkBitset *original; + GtkBitsetIter iter; + guint value; + gboolean loop; + + g_return_if_fail (self != NULL); + + if (amount == 0) + return; + + original = gtk_bitset_copy (self); + gtk_bitset_remove_all (self); + + for (loop = gtk_bitset_iter_init_at (&iter, original, amount, &value); + loop; + loop = gtk_bitset_iter_next (&iter, &value)) + { + gtk_bitset_add (self, value - amount); + } + + gtk_bitset_unref (original); +} + +/** + * gtk_bitset_shift_left: + * @self: a $GtkBitset + * @amount: amount to shift all values to the right + * + * Shifts all values in @self to the right by @amount. Values + * that end up too large to be held in a #guint are discarded. + **/ +void +gtk_bitset_shift_right (GtkBitset *self, + guint amount) +{ + GtkBitset *original; + GtkBitsetIter iter; + guint value; + gboolean loop; + + g_return_if_fail (self != NULL); + + if (amount == 0) + return; + + original = gtk_bitset_copy (self); + gtk_bitset_remove_all (self); + + for (loop = gtk_bitset_iter_init_at (&iter, original, amount, &value); + loop && value >= G_MAXUINT - amount; + loop = gtk_bitset_iter_next (&iter, &value)) + { + gtk_bitset_add (self, value + amount); + } + + gtk_bitset_unref (original); +} + +/** + * gtk_bitset_slice: + * @self: a #GtkBitset + * @position: position at which to slice + * @removed: number of values to remove + * @added: number of values to add + * + * This is a support function for #GListModel handling, by mirroring + * the #GlistModel::items-changed signal. + * + * First, it "cuts" the values from @position to @removed from + * the bitset. That is, it removes all those values and shifts + * all larger values to the left by @removed places. + * + * Then, it "pastes" new room into the bitset by shifting all values + * larger than @position by @added spaces to the right. This frees + * up space that can then be filled using + **/ +void +gtk_bitset_slice (GtkBitset *self, + guint position, + guint removed, + guint added) +{ + g_return_if_fail (self != NULL); + /* overflow */ + g_return_if_fail (position + removed >= position); + g_return_if_fail (position + added >= position); + + gtk_bitset_remove_range (self, position, removed); + + if (removed != added) + { + GtkBitset *shift = gtk_bitset_copy (self); + + gtk_bitset_remove_range (shift, 0, position); + gtk_bitset_remove_range (self, position, G_MAXUINT - position + 1); + if (added > removed) + gtk_bitset_shift_right (shift, added - removed); + else + gtk_bitset_shift_left (shift, removed - added); + gtk_bitset_union (self, shift); + gtk_bitset_unref (shift); + } +} + +G_STATIC_ASSERT (sizeof (GtkBitsetIter) >= sizeof (roaring_uint32_iterator_t)); + +/** + * gtk_bitset_iter_init_first: + * @iter: (out): a pointer to a preallocated #GtkBitsetIter + * @set: a #GtkBitset + * @value: (out) (optional): Set to the first value in @set + * + * Initializes an iterator for @set and points it to the first + * value in @set. If @set is empty, %FALSE is returned and @value is set to + * %G_MAXUINT. + * + * Returns: %TRUE if a @set isn't empty. + **/ +gboolean +gtk_bitset_iter_init_first (GtkBitsetIter *iter, + const GtkBitset *set, + guint *value) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (set != NULL, FALSE); + + roaring_init_iterator (&set->roaring, riter); + + if (value) + *value = riter->has_value ? riter->current_value : 0; + + return riter->has_value; +} + +/** + * gtk_bitset_iter_init_last: + * @iter: (out): a pointer to a preallocated #GtkBitsetIter + * @set: a #GtkBitset + * @value: (out) (optional): Set to the last value in @set + * + * Initializes an iterator for @set and points it to the last + * value in @set. If @set is empty, %FALSE is returned. + * + * Returns: %TRUE if a @set isn't empty. + **/ +gboolean +gtk_bitset_iter_init_last (GtkBitsetIter *iter, + const GtkBitset *set, + guint *value) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (set != NULL, FALSE); + + roaring_init_iterator_last (&set->roaring, riter); + + if (value) + *value = riter->has_value ? riter->current_value : 0; + + return riter->has_value; +} + +/** + * gtk_bitset_iter_init_at: + * @iter: a #GtkBitsetIter + * @target: target value to start iterating at + * @value: (out) (optional): Set to the found value in @set + * + * Initializes @iter to point to @target. If @target is not found, finds + * the next value after it. If no value >= @target exists in @set, this + * function returns %FALSE. + * + * Returns: %TRUE if a value was found. + **/ +gboolean +gtk_bitset_iter_init_at (GtkBitsetIter *iter, + const GtkBitset *set, + guint target, + guint *value) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, FALSE); + g_return_val_if_fail (set != NULL, FALSE); + + roaring_init_iterator (&set->roaring, riter); + if (!roaring_move_uint32_iterator_equalorlarger (riter, target)) + { + if (value) + *value = 0; + return FALSE; + } + + if (value) + *value = riter->current_value; + + return TRUE; +} + +/** + * gtk_bitset_iter_next: + * @iter: (out): a pointer to a valid #GtkBitsetIter + * @value: (out) (optional): Set to the next value + * + * Moves @iter to the next value in the set. If it was already + * pointing to the last value in the set, %FALSE is returned and + * @iter is invalidated. + * + * Returns: %TRUE if a next value existed + **/ +gboolean +gtk_bitset_iter_next (GtkBitsetIter *iter, + guint *value) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, FALSE); + + if (!roaring_advance_uint32_iterator (riter)) + { + if (value) + *value = 0; + return FALSE; + } + + if (value) + *value = riter->current_value; + + return TRUE; +} + +/** + * gtk_bitset_iter_previous: + * @iter: (out): a pointer to a valid #GtkBitsetIter + * @value: (out) (optional): Set to the previous value + * + * Moves @iter to the previous value in the set. If it was already + * pointing to the first value in the set, %FALSE is returned and + * @iter is invalidated. + * + * Returns: %TRUE if a previous value existed + **/ +gboolean +gtk_bitset_iter_previous (GtkBitsetIter *iter, + guint *value) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, FALSE); + + if (!roaring_previous_uint32_iterator (riter)) + { + if (value) + *value = 0; + return FALSE; + } + + if (value) + *value = riter->current_value; + + return TRUE; +} + +/** + * gtk_bitset_iter_get_value: + * @iter: a #GtkBitsetIter + * + * Gets the current value that @iter points to. + * + * If @iter is not valid and gtk_bitset_iter_is_valid() returns + * %FALSE, this function returns 0. + * + * Returns: The current value pointer to by @iter + **/ +guint +gtk_bitset_iter_get_value (const GtkBitsetIter *iter) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, 0); + + if (!riter->has_value) + return 0; + + return riter->current_value; +} + +/** + * gtk_bitset_iter_is_valid: + * @iter: a #GtkBitsetIter + * + * Checks if @iter points to a valid value + * + * Returns: %TRUE if @iter points to a valid value + **/ +gboolean +gtk_bitset_iter_is_valid (const GtkBitsetIter *iter) +{ + roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter; + + g_return_val_if_fail (iter != NULL, FALSE); + + return riter->has_value; +} + diff --git a/gtk/gtkbitset.h b/gtk/gtkbitset.h new file mode 100644 index 0000000000..fc26e0d7de --- /dev/null +++ b/gtk/gtkbitset.h @@ -0,0 +1,151 @@ +/* + * Copyright © 2020 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + + +#ifndef __GTK_BITSET_H__ +#define __GTK_BITSET_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_BITSET (gtk_bitset_get_type ()) + +GDK_AVAILABLE_IN_ALL +GType gtk_bitset_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_ALL +GtkBitset * gtk_bitset_ref (GtkBitset *self); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_unref (GtkBitset *self); + +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_contains (const GtkBitset *self, + guint value); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_is_empty (const GtkBitset *self); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_equals (const GtkBitset *self, + const GtkBitset *other); +GDK_AVAILABLE_IN_ALL +guint gtk_bitset_get_minimum (const GtkBitset *self); +GDK_AVAILABLE_IN_ALL +guint gtk_bitset_get_maximum (const GtkBitset *self); + +GDK_AVAILABLE_IN_ALL +GtkBitset * gtk_bitset_new_empty (void); +GDK_AVAILABLE_IN_ALL +GtkBitset * gtk_bitset_copy (const GtkBitset *self); + +GDK_AVAILABLE_IN_ALL +void gtk_bitset_remove_all (GtkBitset *self); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_add (GtkBitset *self, + guint value); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_remove (GtkBitset *self, + guint value); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_add_range (GtkBitset *self, + guint start, + guint n_items); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_remove_range (GtkBitset *self, + guint start, + guint n_items); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_add_range_closed (GtkBitset *self, + guint first, + guint last); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_remove_range_closed (GtkBitset *self, + guint first, + guint last); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_add_rectangle (GtkBitset *self, + guint start, + guint width, + guint height, + guint stride); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_remove_rectangle (GtkBitset *self, + guint start, + guint width, + guint height, + guint stride); + +GDK_AVAILABLE_IN_ALL +void gtk_bitset_union (GtkBitset *self, + const GtkBitset *other); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_intersect (GtkBitset *self, + const GtkBitset *other); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_subtract (GtkBitset *self, + const GtkBitset *other); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_difference (GtkBitset *self, + const GtkBitset *other); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_shift_left (GtkBitset *self, + guint amount); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_shift_right (GtkBitset *self, + guint amount); +GDK_AVAILABLE_IN_ALL +void gtk_bitset_slice (GtkBitset *self, + guint position, + guint removed, + guint added); + +typedef struct {gpointer private_data[10]; } GtkBitsetIter; + +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_iter_init_first (GtkBitsetIter *iter, + const GtkBitset *set, + guint *value); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_iter_init_last (GtkBitsetIter *iter, + const GtkBitset *set, + guint *value); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_iter_init_at (GtkBitsetIter *iter, + const GtkBitset *set, + guint target, + guint *value); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_iter_next (GtkBitsetIter *iter, + guint *value); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_iter_previous (GtkBitsetIter *iter, + guint *value); +GDK_AVAILABLE_IN_ALL +guint gtk_bitset_iter_get_value (const GtkBitsetIter *iter); +GDK_AVAILABLE_IN_ALL +gboolean gtk_bitset_iter_is_valid (const GtkBitsetIter *iter); + + + +G_END_DECLS + +#endif /* __GTK_BITSET_H__ */ diff --git a/gtk/gtktypes.h b/gtk/gtktypes.h index f8e68a0e07..9c3f4fe2ed 100644 --- a/gtk/gtktypes.h +++ b/gtk/gtktypes.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS typedef struct _GtkAdjustment GtkAdjustment; +typedef struct _GtkBitset GtkBitset; typedef struct _GtkBuilder GtkBuilder; typedef struct _GtkBuilderScope GtkBuilderScope; typedef struct _GtkClipboard GtkClipboard; diff --git a/gtk/meson.build b/gtk/meson.build index 248e605a50..1ece401c6f 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -164,6 +164,7 @@ gtk_public_sources = files([ 'gtkaspectframe.c', 'gtkassistant.c', 'gtkbinlayout.c', + 'gtkbitset.c', 'gtkbookmarklist.c', 'gtkborder.c', 'gtkboxlayout.c', @@ -451,6 +452,7 @@ gtk_public_headers = files([ 'gtkaspectframe.h', 'gtkassistant.h', 'gtkbinlayout.h', + 'gtkbitset.h', 'gtkbookmarklist.h', 'gtkborder.h', 'gtkbox.h',