[gtk/wip/otte/bitset: 2/23] Add GtkBitset



commit 020b0791b1ba843be58e307af7e4390e4a352d3c
Author: Benjamin Otte <otte redhat com>
Date:   Wed Jun 10 08:14:02 2020 +0200

    Add GtkBitset

 gtk/gtk.h       |   1 +
 gtk/gtkbitset.c | 843 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkbitset.h | 151 ++++++++++
 gtk/gtktypes.h  |   1 +
 gtk/meson.build |   2 +
 5 files changed, 998 insertions(+)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index b7600866f9..22964a4887 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -47,6 +47,7 @@
 #include <gtk/gtkaspectframe.h>
 #include <gtk/gtkassistant.h>
 #include <gtk/gtkbinlayout.h>
+#include <gtk/gtkbitset.h>
 #include <gtk/gtkbookmarklist.h>
 #include <gtk/gtkborder.h>
 #include <gtk/gtkboxlayout.h>
diff --git a/gtk/gtkbitset.c b/gtk/gtkbitset.c
new file mode 100644
index 0000000000..7c02c7bf1c
--- /dev/null
+++ b/gtk/gtkbitset.c
@@ -0,0 +1,843 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkbitset.h"
+
+#include "roaring.c"
+
+/**
+ * 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 (&copy->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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+
+#ifndef __GTK_BITSET_H__
+#define __GTK_BITSET_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtktypes.h>
+
+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 83048902a7..3ab5ce8d20 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',
@@ -450,6 +451,7 @@ gtk_public_headers = files([
   'gtkaspectframe.h',
   'gtkassistant.h',
   'gtkbinlayout.h',
+  'gtkbitset.h',
   'gtkbookmarklist.h',
   'gtkborder.h',
   'gtkbox.h',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]