contrib: import GtkBitset as EggBitset

This imports GTK's GtkBitset and the underlying roaring bitmaps so that
we will have it without having to use GTK from libsysprof-analyze.
This commit is contained in:
Christian Hergert
2023-05-25 15:10:35 -07:00
parent 92b3b77dd2
commit 375aaf7086
8 changed files with 19922 additions and 0 deletions

202
contrib/eggbitset/COPYING Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,16 @@
Roaring bitmaps implementation
==============================
This directory contains code modified for GTK, based on the Roaring
bitmaps reference implementation
[CRoaring](https://github.com/RoaringBitmap/CRoaring).
It is not necessarily compatible with past or future versions of CRoaring,
and replacing it with a different version or linking to a system copy
is not supported.
See the source files for copyright and licensing information, and the
`COPYING` file for the full text of the Apache license, version 2.0.
When proposing modifications for these files, please consider whether they
are also suitable for submission to CRoaring.

View File

@ -0,0 +1,984 @@
/*
* 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 "eggbitset.h"
#include "roaring.c"
/**
* EggBitset: (ref-func egg_bitset_ref) (unref-func egg_bitset_unref)
*
* A `EggBitset` represents a set of unsigned integers.
*
* Another name for this data structure is "bitmap".
*
* The current implementation 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. `EggBitset` 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 [struct@Egg.BitsetIter].
*
* The main use case for `EggBitset` is implementing complex selections for
* [iface@Egg.SelectionModel].
*/
struct _EggBitset
{
int ref_count;
roaring_bitmap_t roaring;
};
G_DEFINE_BOXED_TYPE (EggBitset, egg_bitset,
egg_bitset_ref,
egg_bitset_unref)
/**
* egg_bitset_ref:
* @self: (nullable): a `EggBitset`
*
* Acquires a reference on the given `EggBitset`.
*
* Returns: (transfer none): the `EggBitset` with an additional reference
*/
EggBitset *
egg_bitset_ref (EggBitset *self)
{
g_return_val_if_fail (self != NULL, NULL);
self->ref_count += 1;
return self;
}
/**
* egg_bitset_unref:
* @self: (nullable): a `EggBitset`
*
* Releases a reference on the given `EggBitset`.
*
* If the reference was the last, the resources associated to the @self are
* freed.
*/
void
egg_bitset_unref (EggBitset *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_free (self);
}
/**
* egg_bitset_contains:
* @self: a `EggBitset`
* @value: the value to check
*
* Checks if the given @value has been added to @self
*
* Returns: %TRUE if @self contains @value
**/
gboolean
egg_bitset_contains (const EggBitset *self,
guint value)
{
g_return_val_if_fail (self != NULL, FALSE);
return roaring_bitmap_contains (&self->roaring, value);
}
/**
* egg_bitset_is_empty:
* @self: a `EggBitset`
*
* Check if no value is contained in bitset.
*
* Returns: %TRUE if @self is empty
**/
gboolean
egg_bitset_is_empty (const EggBitset *self)
{
g_return_val_if_fail (self != NULL, TRUE);
return roaring_bitmap_is_empty (&self->roaring);
}
/**
* egg_bitset_equals:
* @self: a `EggBitset`
* @other: another `EggBitset`
*
* Returns %TRUE if @self and @other contain the same values.
*
* Returns: %TRUE if @self and @other contain the same values
**/
gboolean
egg_bitset_equals (const EggBitset *self,
const EggBitset *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);
}
/**
* egg_bitset_get_minimum:
* @self: a `EggBitset`
*
* Returns the smallest value in @self.
*
* If @self is empty, `G_MAXUINT` is returned.
*
* Returns: The smallest value in @self
**/
guint
egg_bitset_get_minimum (const EggBitset *self)
{
g_return_val_if_fail (self != NULL, G_MAXUINT);
return roaring_bitmap_minimum (&self->roaring);
}
/**
* egg_bitset_get_maximum:
* @self: a `EggBitset`
*
* Returns the largest value in @self.
*
* If @self is empty, 0 is returned.
*
* Returns: The largest value in @self
**/
guint
egg_bitset_get_maximum (const EggBitset *self)
{
g_return_val_if_fail (self != NULL, 0);
return roaring_bitmap_maximum (&self->roaring);
}
/**
* egg_bitset_get_size:
* @self: a `EggBitset`
*
* Gets the number of values that were added to the set.
*
* For example, if the set is empty, 0 is returned.
*
* Note that this function returns a `guint64`, because when all
* values are set, the return value is `G_MAXUINT + 1`. Unless you
* are sure this cannot happen (it can't with `GListModel`), be sure
* to use a 64bit type.
*
* Returns: The number of values in the set.
*/
guint64
egg_bitset_get_size (const EggBitset *self)
{
g_return_val_if_fail (self != NULL, 0);
return roaring_bitmap_get_cardinality (&self->roaring);
}
/**
* egg_bitset_get_size_in_range:
* @self: a `EggBitset`
* @first: the first element to include
* @last: the last element to include
*
* Gets the number of values that are part of the set from @first to @last
* (inclusive).
*
* Note that this function returns a `guint64`, because when all values are
* set, the return value is `G_MAXUINT + 1`. Unless you are sure this cannot
* happen (it can't with `GListModel`), be sure to use a 64bit type.
*
* Returns: The number of values in the set from @first to @last.
*/
guint64
egg_bitset_get_size_in_range (const EggBitset *self,
guint first,
guint last)
{
g_return_val_if_fail (self != NULL, 0);
g_return_val_if_fail (last >= first, 0);
return roaring_bitmap_range_cardinality (&self->roaring, first, ((uint64_t) last) + 1);
}
/**
* egg_bitset_get_nth:
* @self: a `EggBitset`
* @nth: index of the item to get
*
* Returns the value of the @nth item in self.
*
* If @nth is >= the size of @self, 0 is returned.
*
* Returns: the value of the @nth item in @self
*/
guint
egg_bitset_get_nth (const EggBitset *self,
guint nth)
{
uint32_t result;
if (!roaring_bitmap_select (&self->roaring, nth, &result))
return 0;
return result;
}
/**
* egg_bitset_new_empty:
*
* Creates a new empty bitset.
*
* Returns: A new empty bitset
*/
EggBitset *
egg_bitset_new_empty (void)
{
EggBitset *self;
self = g_new0 (EggBitset, 1);
self->ref_count = 1;
ra_init (&self->roaring.high_low_container);
return self;
}
/**
* egg_bitset_new_range:
* @start: first value to add
* @n_items: number of consecutive values to add
*
* Creates a bitset with the given range set.
*
* Returns: A new bitset
**/
EggBitset *
egg_bitset_new_range (guint start,
guint n_items)
{
EggBitset *self;
self = egg_bitset_new_empty ();
egg_bitset_add_range (self, start, n_items);
return self;
}
/**
* egg_bitset_copy:
* @self: a `EggBitset`
*
* Creates a copy of @self.
*
* Returns: (transfer full): A new bitset that contains the same
* values as @self
*/
EggBitset *
egg_bitset_copy (const EggBitset *self)
{
EggBitset *copy;
g_return_val_if_fail (self != NULL, NULL);
copy = egg_bitset_new_empty ();
roaring_bitmap_overwrite (&copy->roaring, &self->roaring);
return copy;
}
/**
* egg_bitset_remove_all:
* @self: a `EggBitset`
*
* Removes all values from the bitset so that it is empty again.
*/
void
egg_bitset_remove_all (EggBitset *self)
{
g_return_if_fail (self != NULL);
roaring_bitmap_clear (&self->roaring);
}
/**
* egg_bitset_add:
* @self: a `EggBitset`
* @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
egg_bitset_add (EggBitset *self,
guint value)
{
g_return_val_if_fail (self != NULL, FALSE);
return roaring_bitmap_add_checked (&self->roaring, value);
}
/**
* egg_bitset_remove:
* @self: a `EggBitset`
* @value: value to remove
*
* Removes @value from @self if it was part of it before.
*
* Returns: %TRUE if @value was part of @self and @self
* was changed
*/
gboolean
egg_bitset_remove (EggBitset *self,
guint value)
{
g_return_val_if_fail (self != NULL, FALSE);
return roaring_bitmap_remove_checked (&self->roaring, value);
}
/**
* egg_bitset_add_range:
* @self: a `EggBitset`
* @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
egg_bitset_add_range (EggBitset *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);
}
/**
* egg_bitset_remove_range:
* @self: a `EggBitset`
* @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
egg_bitset_remove_range (EggBitset *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);
}
/**
* egg_bitset_add_range_closed:
* @self: a `EggBitset`
* @first: first value to add
* @last: last value to add
*
* Adds the closed range [@first, @last], so @first, @last and all
* values in between. @first must be smaller than @last.
*/
void
egg_bitset_add_range_closed (EggBitset *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);
}
/**
* egg_bitset_remove_range_closed:
* @self: a `EggBitset`
* @first: first value to remove
* @last: last value to remove
*
* Removes the closed range [@first, @last], so @first, @last and all
* values in between. @first must be smaller than @last.
*/
void
egg_bitset_remove_range_closed (EggBitset *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);
}
/**
* egg_bitset_add_rectangle:
* @self: a `EggBitset`
* @start: first value to add
* @width: width of the rectangle
* @height: height of the rectangle
* @stride: row stride of the grid
*
* 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
egg_bitset_add_rectangle (EggBitset *self,
guint start,
guint width,
guint height,
guint stride)
{
guint i;
g_return_if_fail (self != NULL);
g_return_if_fail ((start % stride) + width <= stride);
g_return_if_fail (G_MAXUINT - start >= height * stride);
if (width == 0 || height == 0)
return;
for (i = 0; i < height; i++)
egg_bitset_add_range (self, i * stride + start, width);
}
/**
* egg_bitset_remove_rectangle:
* @self: a `EggBitset`
* @start: first value to remove
* @width: width of the rectangle
* @height: height of the rectangle
* @stride: row stride of the grid
*
* 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
egg_bitset_remove_rectangle (EggBitset *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++)
egg_bitset_remove_range (self, i * stride + start, width);
}
/**
* egg_bitset_union:
* @self: a `EggBitset`
* @other: the `EggBitset` 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
egg_bitset_union (EggBitset *self,
const EggBitset *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);
}
/**
* egg_bitset_intersect:
* @self: a `EggBitset`
* @other: the `EggBitset` to intersect with
*
* Sets @self to be the intersection of @self and @other.
*
* In other words, 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
egg_bitset_intersect (EggBitset *self,
const EggBitset *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);
}
/**
* egg_bitset_subtract:
* @self: a `EggBitset`
* @other: the `EggBitset` to subtract
*
* Sets @self to be the subtraction of @other from @self.
*
* In other words, 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
egg_bitset_subtract (EggBitset *self,
const EggBitset *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);
}
/**
* egg_bitset_difference:
* @self: a `EggBitset`
* @other: the `EggBitset` to compute the difference from
*
* Sets @self to be the symmetric difference of @self and @other.
*
* The symmetric difference 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
egg_bitset_difference (EggBitset *self,
const EggBitset *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);
}
/**
* egg_bitset_shift_left:
* @self: a `EggBitset`
* @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
egg_bitset_shift_left (EggBitset *self,
guint amount)
{
EggBitset *original;
EggBitsetIter iter;
guint value;
gboolean loop;
g_return_if_fail (self != NULL);
if (amount == 0)
return;
original = egg_bitset_copy (self);
egg_bitset_remove_all (self);
for (loop = egg_bitset_iter_init_at (&iter, original, amount, &value);
loop;
loop = egg_bitset_iter_next (&iter, &value))
{
egg_bitset_add (self, value - amount);
}
egg_bitset_unref (original);
}
/**
* egg_bitset_shift_right:
* @self: a `EggBitset`
* @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
egg_bitset_shift_right (EggBitset *self,
guint amount)
{
EggBitset *original;
EggBitsetIter iter;
guint value;
gboolean loop;
g_return_if_fail (self != NULL);
if (amount == 0)
return;
original = egg_bitset_copy (self);
egg_bitset_remove_all (self);
for (loop = egg_bitset_iter_init_first (&iter, original, &value);
loop && value <= G_MAXUINT - amount;
loop = egg_bitset_iter_next (&iter, &value))
{
egg_bitset_add (self, value + amount);
}
egg_bitset_unref (original);
}
/**
* egg_bitset_splice:
* @self: a `EggBitset`
* @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.
*/
void
egg_bitset_splice (EggBitset *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);
egg_bitset_remove_range (self, position, removed);
if (removed != added)
{
EggBitset *shift = egg_bitset_copy (self);
egg_bitset_remove_range (shift, 0, position);
egg_bitset_remove_range_closed (self, position, G_MAXUINT);
if (added > removed)
egg_bitset_shift_right (shift, added - removed);
else
egg_bitset_shift_left (shift, removed - added);
egg_bitset_union (self, shift);
egg_bitset_unref (shift);
}
}
G_STATIC_ASSERT (sizeof (EggBitsetIter) >= sizeof (roaring_uint32_iterator_t));
static EggBitsetIter *
egg_bitset_iter_copy (EggBitsetIter *iter)
{
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
return (EggBitsetIter *) roaring_copy_uint32_iterator (riter);
}
static void
egg_bitset_iter_free (EggBitsetIter *iter)
{
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
roaring_free_uint32_iterator (riter);
}
G_DEFINE_BOXED_TYPE (EggBitsetIter, egg_bitset_iter, egg_bitset_iter_copy, egg_bitset_iter_free)
/**
* egg_bitset_iter_init_first:
* @iter: (out): a pointer to an uninitialized `EggBitsetIter`
* @set: a `EggBitset`
* @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 @set isn't empty.
*/
gboolean
egg_bitset_iter_init_first (EggBitsetIter *iter,
const EggBitset *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;
}
/**
* egg_bitset_iter_init_last:
* @iter: (out): a pointer to an uninitialized `EggBitsetIter`
* @set: a `EggBitset`
* @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 @set isn't empty.
**/
gboolean
egg_bitset_iter_init_last (EggBitsetIter *iter,
const EggBitset *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;
}
/**
* egg_bitset_iter_init_at:
* @iter: (out): a pointer to an uninitialized `EggBitsetIter`
* @set: a `EggBitset`
* @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
egg_bitset_iter_init_at (EggBitsetIter *iter,
const EggBitset *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;
}
/**
* egg_bitset_iter_next:
* @iter: a pointer to a valid `EggBitsetIter`
* @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
egg_bitset_iter_next (EggBitsetIter *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;
}
/**
* egg_bitset_iter_previous:
* @iter: a pointer to a valid `EggBitsetIter`
* @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
egg_bitset_iter_previous (EggBitsetIter *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;
}
/**
* egg_bitset_iter_get_value:
* @iter: a `EggBitsetIter`
*
* Gets the current value that @iter points to.
*
* If @iter is not valid and [method@Egg.BitsetIter.is_valid]
* returns %FALSE, this function returns 0.
*
* Returns: The current value pointer to by @iter
*/
guint
egg_bitset_iter_get_value (const EggBitsetIter *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;
}
/**
* egg_bitset_iter_is_valid:
* @iter: a `EggBitsetIter`
*
* Checks if @iter points to a valid value.
*
* Returns: %TRUE if @iter points to a valid value
*/
gboolean
egg_bitset_iter_is_valid (const EggBitsetIter *iter)
{
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
g_return_val_if_fail (iter != NULL, FALSE);
return riter->has_value;
}

View File

@ -0,0 +1,137 @@
/*
* 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>
*/
#pragma once
#include <glib-object.h>
G_BEGIN_DECLS
#define EGG_TYPE_BITSET (egg_bitset_get_type ())
typedef struct _EggBitset EggBitset;
GType egg_bitset_get_type (void) G_GNUC_CONST;
EggBitset * egg_bitset_ref (EggBitset *self);
void egg_bitset_unref (EggBitset *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(EggBitset, egg_bitset_unref)
gboolean egg_bitset_contains (const EggBitset *self,
guint value);
gboolean egg_bitset_is_empty (const EggBitset *self);
gboolean egg_bitset_equals (const EggBitset *self,
const EggBitset *other);
guint64 egg_bitset_get_size (const EggBitset *self);
guint64 egg_bitset_get_size_in_range (const EggBitset *self,
guint first,
guint last);
guint egg_bitset_get_nth (const EggBitset *self,
guint nth);
guint egg_bitset_get_minimum (const EggBitset *self);
guint egg_bitset_get_maximum (const EggBitset *self);
EggBitset * egg_bitset_new_empty (void);
EggBitset * egg_bitset_copy (const EggBitset *self);
EggBitset * egg_bitset_new_range (guint start,
guint n_items);
void egg_bitset_remove_all (EggBitset *self);
gboolean egg_bitset_add (EggBitset *self,
guint value);
gboolean egg_bitset_remove (EggBitset *self,
guint value);
void egg_bitset_add_range (EggBitset *self,
guint start,
guint n_items);
void egg_bitset_remove_range (EggBitset *self,
guint start,
guint n_items);
void egg_bitset_add_range_closed (EggBitset *self,
guint first,
guint last);
void egg_bitset_remove_range_closed (EggBitset *self,
guint first,
guint last);
void egg_bitset_add_rectangle (EggBitset *self,
guint start,
guint width,
guint height,
guint stride);
void egg_bitset_remove_rectangle (EggBitset *self,
guint start,
guint width,
guint height,
guint stride);
void egg_bitset_union (EggBitset *self,
const EggBitset *other);
void egg_bitset_intersect (EggBitset *self,
const EggBitset *other);
void egg_bitset_subtract (EggBitset *self,
const EggBitset *other);
void egg_bitset_difference (EggBitset *self,
const EggBitset *other);
void egg_bitset_shift_left (EggBitset *self,
guint amount);
void egg_bitset_shift_right (EggBitset *self,
guint amount);
void egg_bitset_splice (EggBitset *self,
guint position,
guint removed,
guint added);
/**
* EggBitsetIter:
*
* An opaque, stack-allocated struct for iterating
* over the elements of a `EggBitset`.
*
* Before a `EggBitsetIter` can be used, it needs to be initialized with
* [func@Egg.BitsetIter.init_first], [func@Egg.BitsetIter.init_last]
* or [func@Egg.BitsetIter.init_at].
*/
typedef struct _EggBitsetIter EggBitsetIter;
struct _EggBitsetIter
{
/*< private >*/
gpointer private_data[10];
};
GType egg_bitset_iter_get_type (void) G_GNUC_CONST;
gboolean egg_bitset_iter_init_first (EggBitsetIter *iter,
const EggBitset *set,
guint *value);
gboolean egg_bitset_iter_init_last (EggBitsetIter *iter,
const EggBitset *set,
guint *value);
gboolean egg_bitset_iter_init_at (EggBitsetIter *iter,
const EggBitset *set,
guint target,
guint *value);
gboolean egg_bitset_iter_next (EggBitsetIter *iter,
guint *value);
gboolean egg_bitset_iter_previous (EggBitsetIter *iter,
guint *value);
guint egg_bitset_iter_get_value (const EggBitsetIter *iter);
gboolean egg_bitset_iter_is_valid (const EggBitsetIter *iter);
G_END_DECLS

View File

@ -0,0 +1,17 @@
libeggbitset_sources = [
'eggbitset.c',
]
libeggbitset_deps = [
dependency('gio-2.0', version: glib_req_version),
]
libeggbitset_static = static_library('eggbitset', libeggbitset_sources,
gnu_symbol_visibility: 'hidden',
dependencies: libeggbitset_deps,
)
libeggbitset_static_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: libeggbitset_static,
)

11475
contrib/eggbitset/roaring.c Normal file

File diff suppressed because it is too large Load Diff

7090
contrib/eggbitset/roaring.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,2 @@
subdir('eggbitset')
subdir('elfparser')