diff --git a/.gitignore b/.gitignore
index 1682ae21..ed98732c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.flatpak-builder
*.swp
*~
build
diff --git a/config.h.meson b/config.h.meson
index 34be5f6a..b002f492 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -16,6 +16,8 @@
#mesondefine HAVE_EXECINFO_H
+#mesondefine HAVE_LIBSYSTEMD
+
#mesondefine HAVE_PERF_CLOCKID
#mesondefine HAVE_POLKIT
diff --git a/contrib/eggbitset/COPYING b/contrib/eggbitset/COPYING
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/contrib/eggbitset/COPYING
@@ -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.
diff --git a/contrib/eggbitset/README.md b/contrib/eggbitset/README.md
new file mode 100644
index 00000000..9404a84b
--- /dev/null
+++ b/contrib/eggbitset/README.md
@@ -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.
diff --git a/contrib/eggbitset/eggbitset.c b/contrib/eggbitset/eggbitset.c
new file mode 100644
index 00000000..f1d45d6f
--- /dev/null
+++ b/contrib/eggbitset/eggbitset.c
@@ -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 .
+ *
+ * Authors: Benjamin Otte
+ */
+
+#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 (©->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;
+}
diff --git a/contrib/eggbitset/eggbitset.h b/contrib/eggbitset/eggbitset.h
new file mode 100644
index 00000000..3127ce2c
--- /dev/null
+++ b/contrib/eggbitset/eggbitset.h
@@ -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 .
+ *
+ * Authors: Benjamin Otte
+ */
+
+
+#pragma once
+
+#include
+
+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
+
diff --git a/contrib/eggbitset/meson.build b/contrib/eggbitset/meson.build
new file mode 100644
index 00000000..0b5fd036
--- /dev/null
+++ b/contrib/eggbitset/meson.build
@@ -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,
+)
diff --git a/contrib/eggbitset/roaring.c b/contrib/eggbitset/roaring.c
new file mode 100644
index 00000000..ff883844
--- /dev/null
+++ b/contrib/eggbitset/roaring.c
@@ -0,0 +1,11475 @@
+/*
+ * Amalgamated copy of CRoaring 0.2.66, modified for GTK to reduce compiler
+ * warnings.
+ *
+ * Copyright 2016-2020 The CRoaring authors
+ * Copyright 2020 Benjamin Otte
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
+
+#include "roaring.h"
+
+/* used for http://dmalloc.com/ Dmalloc - Debug Malloc Library */
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/* begin file src/array_util.c */
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#ifdef USESSE4
+// used by intersect_vector16
+ALIGNED(0x1000)
+static const uint8_t shuffle_mask16[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 6, 7, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 8, 9,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 8, 9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 8, 9,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 8, 9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 6, 7, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7, 8, 9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7,
+ 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 6, 7, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7, 8, 9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 6, 7, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 6, 7, 8, 9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 10, 11, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 10, 11, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 6, 7, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 6, 7, 10, 11,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 6, 7, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 6, 7, 10, 11,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 6, 7, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 8, 9, 10, 11, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 8, 9,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 8, 9, 10, 11, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 8, 9,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 8, 9,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 6, 7, 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7, 8, 9, 10, 11,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 6, 7, 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 6, 7, 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 6, 7, 8, 9,
+ 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 0xFF, 0xFF, 0xFF, 0xFF, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 6, 7, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 6, 7, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 6, 7, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 6, 7, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 6, 7,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 8, 9, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 8, 9, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 8, 9, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 8, 9, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7,
+ 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 6, 7, 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 6, 7, 8, 9,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7,
+ 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 6, 7, 8, 9, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 6, 7, 8, 9,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 10, 11, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 10, 11, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 6, 7, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7, 10, 11, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 6, 7, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 6, 7, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 6, 7, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 6, 7, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 10, 11, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 8, 9,
+ 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 8, 9, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 8, 9,
+ 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 8, 9, 10, 11, 12, 13, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 8, 9, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 6, 7, 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7, 8, 9, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7,
+ 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 0xFF, 0xFF, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 6, 7, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 6, 7, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 6, 7, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 6, 7, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 6, 7, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 8, 9, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 8, 9,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 8, 9, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 8, 9,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 8, 9,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 6, 7, 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7, 8, 9, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 6, 7, 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 6, 7, 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 6, 7, 8, 9,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 6, 7, 8, 9, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 10, 11,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 10, 11,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 6, 7, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7,
+ 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 6, 7, 10, 11, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 6, 7, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 6, 7, 10, 11, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 6, 7,
+ 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 10, 11,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 8, 9, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 8, 9, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 8, 9, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 8, 9, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 8, 9, 10, 11,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 8, 9, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 8, 9, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7,
+ 8, 9, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 6, 7, 8, 9, 10, 11, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 6, 7, 8, 9,
+ 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7,
+ 8, 9, 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 0xFF, 0xFF,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 12, 13, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 12, 13, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 6, 7, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 6, 7, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 6, 7, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 6, 7, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 6, 7, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 12, 13, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 8, 9,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 8, 9, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 8, 9, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 8, 9,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 8, 9, 12, 13, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 8, 9, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 8, 9, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 6, 7, 8, 9, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7, 8, 9, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7,
+ 8, 9, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7, 8, 9, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 6, 7, 8, 9, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 6, 7, 8, 9, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 12, 13, 14, 15, 0xFF, 0xFF, 10, 11, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 4, 5, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 10, 11, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 6, 7, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 6, 7,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 6, 7, 10, 11,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 6, 7,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 4, 5, 6, 7, 10, 11,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF,
+ 8, 9, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 8, 9, 10, 11, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 8, 9,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 8, 9, 10, 11, 12, 13,
+ 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5,
+ 8, 9, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF,
+ 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, 5, 8, 9,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0, 1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 2, 3, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0, 1, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 0xFF, 0xFF, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xFF, 0xFF,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15};
+
+/**
+ * From Schlegel et al., Fast Sorted-Set Intersection using SIMD Instructions
+ * Optimized by D. Lemire on May 3rd 2013
+ */
+int32_t intersect_vector16(const uint16_t *__restrict__ A, size_t s_a,
+ const uint16_t *__restrict__ B, size_t s_b,
+ uint16_t *C) {
+ size_t count = 0;
+ size_t i_a = 0, i_b = 0;
+ const int vectorlength = sizeof(__m128i) / sizeof(uint16_t);
+ const size_t st_a = (s_a / vectorlength) * vectorlength;
+ const size_t st_b = (s_b / vectorlength) * vectorlength;
+ __m128i v_a, v_b;
+ if ((i_a < st_a) && (i_b < st_b)) {
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ while ((A[i_a] == 0) || (B[i_b] == 0)) {
+ const __m128i res_v = _mm_cmpestrm(
+ v_b, vectorlength, v_a, vectorlength,
+ _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK);
+ const int r = _mm_extract_epi32(res_v, 0);
+ __m128i sm16 = _mm_load_si128((const __m128i *)shuffle_mask16 + r);
+ __m128i p = _mm_shuffle_epi8(v_a, sm16);
+ _mm_storeu_si128((__m128i *)&C[count], p); // can overflow
+ count += _mm_popcnt_u32(r);
+ const uint16_t a_max = A[i_a + vectorlength - 1];
+ const uint16_t b_max = B[i_b + vectorlength - 1];
+ if (a_max <= b_max) {
+ i_a += vectorlength;
+ if (i_a == st_a) break;
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ }
+ if (b_max <= a_max) {
+ i_b += vectorlength;
+ if (i_b == st_b) break;
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ }
+ }
+ if ((i_a < st_a) && (i_b < st_b))
+ while (true) {
+ const __m128i res_v = _mm_cmpistrm(
+ v_b, v_a,
+ _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK);
+ const int r = _mm_extract_epi32(res_v, 0);
+ __m128i sm16 =
+ _mm_load_si128((const __m128i *)shuffle_mask16 + r);
+ __m128i p = _mm_shuffle_epi8(v_a, sm16);
+ _mm_storeu_si128((__m128i *)&C[count], p); // can overflow
+ count += _mm_popcnt_u32(r);
+ const uint16_t a_max = A[i_a + vectorlength - 1];
+ const uint16_t b_max = B[i_b + vectorlength - 1];
+ if (a_max <= b_max) {
+ i_a += vectorlength;
+ if (i_a == st_a) break;
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ }
+ if (b_max <= a_max) {
+ i_b += vectorlength;
+ if (i_b == st_b) break;
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ }
+ }
+ }
+ // intersect the tail using scalar intersection
+ while (i_a < s_a && i_b < s_b) {
+ uint16_t a = A[i_a];
+ uint16_t b = B[i_b];
+ if (a < b) {
+ i_a++;
+ } else if (b < a) {
+ i_b++;
+ } else {
+ C[count] = a; //==b;
+ count++;
+ i_a++;
+ i_b++;
+ }
+ }
+ return (int32_t)count;
+}
+
+int32_t intersect_vector16_cardinality(const uint16_t *__restrict__ A,
+ size_t s_a,
+ const uint16_t *__restrict__ B,
+ size_t s_b) {
+ size_t count = 0;
+ size_t i_a = 0, i_b = 0;
+ const int vectorlength = sizeof(__m128i) / sizeof(uint16_t);
+ const size_t st_a = (s_a / vectorlength) * vectorlength;
+ const size_t st_b = (s_b / vectorlength) * vectorlength;
+ __m128i v_a, v_b;
+ if ((i_a < st_a) && (i_b < st_b)) {
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ while ((A[i_a] == 0) || (B[i_b] == 0)) {
+ const __m128i res_v = _mm_cmpestrm(
+ v_b, vectorlength, v_a, vectorlength,
+ _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK);
+ const int r = _mm_extract_epi32(res_v, 0);
+ count += _mm_popcnt_u32(r);
+ const uint16_t a_max = A[i_a + vectorlength - 1];
+ const uint16_t b_max = B[i_b + vectorlength - 1];
+ if (a_max <= b_max) {
+ i_a += vectorlength;
+ if (i_a == st_a) break;
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ }
+ if (b_max <= a_max) {
+ i_b += vectorlength;
+ if (i_b == st_b) break;
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ }
+ }
+ if ((i_a < st_a) && (i_b < st_b))
+ while (true) {
+ const __m128i res_v = _mm_cmpistrm(
+ v_b, v_a,
+ _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK);
+ const int r = _mm_extract_epi32(res_v, 0);
+ count += _mm_popcnt_u32(r);
+ const uint16_t a_max = A[i_a + vectorlength - 1];
+ const uint16_t b_max = B[i_b + vectorlength - 1];
+ if (a_max <= b_max) {
+ i_a += vectorlength;
+ if (i_a == st_a) break;
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ }
+ if (b_max <= a_max) {
+ i_b += vectorlength;
+ if (i_b == st_b) break;
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ }
+ }
+ }
+ // intersect the tail using scalar intersection
+ while (i_a < s_a && i_b < s_b) {
+ uint16_t a = A[i_a];
+ uint16_t b = B[i_b];
+ if (a < b) {
+ i_a++;
+ } else if (b < a) {
+ i_b++;
+ } else {
+ count++;
+ i_a++;
+ i_b++;
+ }
+ }
+ return (int32_t)count;
+}
+
+/////////
+// Warning:
+// This function may not be safe if A == C or B == C.
+/////////
+int32_t difference_vector16(const uint16_t *__restrict__ A, size_t s_a,
+ const uint16_t *__restrict__ B, size_t s_b,
+ uint16_t *C) {
+ // we handle the degenerate case
+ if (s_a == 0) return 0;
+ if (s_b == 0) {
+ if (A != C) memcpy(C, A, sizeof(uint16_t) * s_a);
+ return (int32_t)s_a;
+ }
+ // handle the leading zeroes, it is messy but it allows us to use the fast
+ // _mm_cmpistrm intrinsic safely
+ int32_t count = 0;
+ if ((A[0] == 0) || (B[0] == 0)) {
+ if ((A[0] == 0) && (B[0] == 0)) {
+ A++;
+ s_a--;
+ B++;
+ s_b--;
+ } else if (A[0] == 0) {
+ C[count++] = 0;
+ A++;
+ s_a--;
+ } else {
+ B++;
+ s_b--;
+ }
+ }
+ // at this point, we have two non-empty arrays, made of non-zero
+ // increasing values.
+ size_t i_a = 0, i_b = 0;
+ const size_t vectorlength = sizeof(__m128i) / sizeof(uint16_t);
+ const size_t st_a = (s_a / vectorlength) * vectorlength;
+ const size_t st_b = (s_b / vectorlength) * vectorlength;
+ if ((i_a < st_a) && (i_b < st_b)) { // this is the vectorized code path
+ __m128i v_a, v_b; //, v_bmax;
+ // we load a vector from A and a vector from B
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ // we have a runningmask which indicates which values from A have been
+ // spotted in B, these don't get written out.
+ __m128i runningmask_a_found_in_b = _mm_setzero_si128();
+ /****
+ * start of the main vectorized loop
+ *****/
+ while (true) {
+ // afoundinb will contain a mask indicate for each entry in A
+ // whether it is seen
+ // in B
+ const __m128i a_found_in_b =
+ _mm_cmpistrm(v_b, v_a, _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_ANY |
+ _SIDD_BIT_MASK);
+ runningmask_a_found_in_b =
+ _mm_or_si128(runningmask_a_found_in_b, a_found_in_b);
+ // we always compare the last values of A and B
+ const uint16_t a_max = A[i_a + vectorlength - 1];
+ const uint16_t b_max = B[i_b + vectorlength - 1];
+ if (a_max <= b_max) {
+ // Ok. In this code path, we are ready to write our v_a
+ // because there is no need to read more from B, they will
+ // all be large values.
+ const int bitmask_belongs_to_difference =
+ _mm_extract_epi32(runningmask_a_found_in_b, 0) ^ 0xFF;
+ /*** next few lines are probably expensive *****/
+ __m128i sm16 = _mm_load_si128((const __m128i *)shuffle_mask16 +
+ bitmask_belongs_to_difference);
+ __m128i p = _mm_shuffle_epi8(v_a, sm16);
+ _mm_storeu_si128((__m128i *)&C[count], p); // can overflow
+ count += _mm_popcnt_u32(bitmask_belongs_to_difference);
+ // we advance a
+ i_a += vectorlength;
+ if (i_a == st_a) // no more
+ break;
+ runningmask_a_found_in_b = _mm_setzero_si128();
+ v_a = _mm_lddqu_si128((__m128i *)&A[i_a]);
+ }
+ if (b_max <= a_max) {
+ // in this code path, the current v_b has become useless
+ i_b += vectorlength;
+ if (i_b == st_b) break;
+ v_b = _mm_lddqu_si128((__m128i *)&B[i_b]);
+ }
+ }
+ // at this point, either we have i_a == st_a, which is the end of the
+ // vectorized processing,
+ // or we have i_b == st_b, and we are not done processing the vector...
+ // so we need to finish it off.
+ if (i_a < st_a) { // we have unfinished business...
+ uint16_t buffer[8]; // buffer to do a masked load
+ memset(buffer, 0, 8 * sizeof(uint16_t));
+ memcpy(buffer, B + i_b, (s_b - i_b) * sizeof(uint16_t));
+ v_b = _mm_lddqu_si128((__m128i *)buffer);
+ const __m128i a_found_in_b =
+ _mm_cmpistrm(v_b, v_a, _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_ANY |
+ _SIDD_BIT_MASK);
+ runningmask_a_found_in_b =
+ _mm_or_si128(runningmask_a_found_in_b, a_found_in_b);
+ const int bitmask_belongs_to_difference =
+ _mm_extract_epi32(runningmask_a_found_in_b, 0) ^ 0xFF;
+ __m128i sm16 = _mm_load_si128((const __m128i *)shuffle_mask16 +
+ bitmask_belongs_to_difference);
+ __m128i p = _mm_shuffle_epi8(v_a, sm16);
+ _mm_storeu_si128((__m128i *)&C[count], p); // can overflow
+ count += _mm_popcnt_u32(bitmask_belongs_to_difference);
+ i_a += vectorlength;
+ }
+ // at this point we should have i_a == st_a and i_b == st_b
+ }
+ // do the tail using scalar code
+ while (i_a < s_a && i_b < s_b) {
+ uint16_t a = A[i_a];
+ uint16_t b = B[i_b];
+ if (b < a) {
+ i_b++;
+ } else if (a < b) {
+ C[count] = a;
+ count++;
+ i_a++;
+ } else { //==
+ i_a++;
+ i_b++;
+ }
+ }
+ if (i_a < s_a) {
+ if(C == A) {
+ assert((size_t)count <= i_a);
+ if((size_t)count < i_a) {
+ memmove(C + count, A + i_a, sizeof(uint16_t) * (s_a - i_a));
+ }
+ } else {
+ for(size_t i = 0; i < (s_a - i_a); i++) {
+ C[count + i] = A[i + i_a];
+ }
+ }
+ count += (int32_t)(s_a - i_a);
+ }
+ return count;
+}
+
+#endif // USESSE4
+
+
+
+#ifdef USE_OLD_SKEW_INTERSECT
+// TODO: given enough experience with the new skew intersect, drop the old one from the code base.
+
+
+/* Computes the intersection between one small and one large set of uint16_t.
+ * Stores the result into buffer and return the number of elements. */
+int32_t intersect_skewed_uint16(const uint16_t *small, size_t size_s,
+ const uint16_t *large, size_t size_l,
+ uint16_t *buffer) {
+ size_t pos = 0, idx_l = 0, idx_s = 0;
+
+ if (0 == size_s) {
+ return 0;
+ }
+
+ uint16_t val_l = large[idx_l], val_s = small[idx_s];
+
+ while (true) {
+ if (val_l < val_s) {
+ idx_l = advanceUntil(large, (int32_t)idx_l, (int32_t)size_l, val_s);
+ if (idx_l == size_l) break;
+ val_l = large[idx_l];
+ } else if (val_s < val_l) {
+ idx_s++;
+ if (idx_s == size_s) break;
+ val_s = small[idx_s];
+ } else {
+ buffer[pos++] = val_s;
+ idx_s++;
+ if (idx_s == size_s) break;
+ val_s = small[idx_s];
+ idx_l = advanceUntil(large, (int32_t)idx_l, (int32_t)size_l, val_s);
+ if (idx_l == size_l) break;
+ val_l = large[idx_l];
+ }
+ }
+
+ return (int32_t)pos;
+}
+#else // USE_OLD_SKEW_INTERSECT
+
+
+/**
+* Branchless binary search going after 4 values at once.
+* Assumes that array is sorted.
+* You have that array[*index1] >= target1, array[*index12] >= target2, ...
+* except when *index1 = n, in which case you know that all values in array are
+* smaller than target1, and so forth.
+* It has logarithmic complexity.
+*/
+static void binarySearch4(const uint16_t *array, int32_t n, uint16_t target1,
+ uint16_t target2, uint16_t target3, uint16_t target4,
+ int32_t *index1, int32_t *index2, int32_t *index3,
+ int32_t *index4) {
+ const uint16_t *base1 = array;
+ const uint16_t *base2 = array;
+ const uint16_t *base3 = array;
+ const uint16_t *base4 = array;
+ if (n == 0)
+ return;
+ while (n > 1) {
+ int32_t half = n >> 1;
+ base1 = (base1[half] < target1) ? &base1[half] : base1;
+ base2 = (base2[half] < target2) ? &base2[half] : base2;
+ base3 = (base3[half] < target3) ? &base3[half] : base3;
+ base4 = (base4[half] < target4) ? &base4[half] : base4;
+ n -= half;
+ }
+ *index1 = (int32_t)((*base1 < target1) + base1 - array);
+ *index2 = (int32_t)((*base2 < target2) + base2 - array);
+ *index3 = (int32_t)((*base3 < target3) + base3 - array);
+ *index4 = (int32_t)((*base4 < target4) + base4 - array);
+}
+
+/**
+* Branchless binary search going after 2 values at once.
+* Assumes that array is sorted.
+* You have that array[*index1] >= target1, array[*index12] >= target2.
+* except when *index1 = n, in which case you know that all values in array are
+* smaller than target1, and so forth.
+* It has logarithmic complexity.
+*/
+static void binarySearch2(const uint16_t *array, int32_t n, uint16_t target1,
+ uint16_t target2, int32_t *index1, int32_t *index2) {
+ const uint16_t *base1 = array;
+ const uint16_t *base2 = array;
+ if (n == 0)
+ return;
+ while (n > 1) {
+ int32_t half = n >> 1;
+ base1 = (base1[half] < target1) ? &base1[half] : base1;
+ base2 = (base2[half] < target2) ? &base2[half] : base2;
+ n -= half;
+ }
+ *index1 = (int32_t)((*base1 < target1) + base1 - array);
+ *index2 = (int32_t)((*base2 < target2) + base2 - array);
+}
+
+/* Computes the intersection between one small and one large set of uint16_t.
+ * Stores the result into buffer and return the number of elements.
+ * Processes the small set in blocks of 4 values calling binarySearch4
+ * and binarySearch2. This approach can be slightly superior to a conventional
+ * galloping search in some instances.
+ */
+int32_t intersect_skewed_uint16(const uint16_t *small, size_t size_s,
+ const uint16_t *large, size_t size_l,
+ uint16_t *buffer) {
+ size_t pos = 0, idx_l = 0, idx_s = 0;
+
+ if (0 == size_s) {
+ return 0;
+ }
+ int32_t index1 = 0, index2 = 0, index3 = 0, index4 = 0;
+ while ((idx_s + 4 <= size_s) && (idx_l < size_l)) {
+ uint16_t target1 = small[idx_s];
+ uint16_t target2 = small[idx_s + 1];
+ uint16_t target3 = small[idx_s + 2];
+ uint16_t target4 = small[idx_s + 3];
+ binarySearch4(large + idx_l, (int32_t)(size_l - idx_l), target1, target2, target3,
+ target4, &index1, &index2, &index3, &index4);
+ if ((index1 + idx_l < size_l) && (large[idx_l + index1] == target1)) {
+ buffer[pos++] = target1;
+ }
+ if ((index2 + idx_l < size_l) && (large[idx_l + index2] == target2)) {
+ buffer[pos++] = target2;
+ }
+ if ((index3 + idx_l < size_l) && (large[idx_l + index3] == target3)) {
+ buffer[pos++] = target3;
+ }
+ if ((index4 + idx_l < size_l) && (large[idx_l + index4] == target4)) {
+ buffer[pos++] = target4;
+ }
+ idx_s += 4;
+ idx_l += index4;
+ }
+ if ((idx_s + 2 <= size_s) && (idx_l < size_l)) {
+ uint16_t target1 = small[idx_s];
+ uint16_t target2 = small[idx_s + 1];
+ binarySearch2(large + idx_l, (int32_t)(size_l - idx_l), target1, target2, &index1,
+ &index2);
+ if ((index1 + idx_l < size_l) && (large[idx_l + index1] == target1)) {
+ buffer[pos++] = target1;
+ }
+ if ((index2 + idx_l < size_l) && (large[idx_l + index2] == target2)) {
+ buffer[pos++] = target2;
+ }
+ idx_s += 2;
+ idx_l += index2;
+ }
+ if ((idx_s < size_s) && (idx_l < size_l)) {
+ uint16_t val_s = small[idx_s];
+ int32_t index = binarySearch(large + idx_l, (int32_t)(size_l - idx_l), val_s);
+ if (index >= 0)
+ buffer[pos++] = val_s;
+ }
+ return (int32_t)pos;
+}
+
+
+#endif //USE_OLD_SKEW_INTERSECT
+
+
+// TODO: this could be accelerated, possibly, by using binarySearch4 as above.
+int32_t intersect_skewed_uint16_cardinality(const uint16_t *small,
+ size_t size_s,
+ const uint16_t *large,
+ size_t size_l) {
+ size_t pos = 0, idx_l = 0, idx_s = 0;
+
+ if (0 == size_s) {
+ return 0;
+ }
+
+ uint16_t val_l = large[idx_l], val_s = small[idx_s];
+
+ while (true) {
+ if (val_l < val_s) {
+ idx_l = advanceUntil(large, (int32_t)idx_l, (int32_t)size_l, val_s);
+ if (idx_l == size_l) break;
+ val_l = large[idx_l];
+ } else if (val_s < val_l) {
+ idx_s++;
+ if (idx_s == size_s) break;
+ val_s = small[idx_s];
+ } else {
+ pos++;
+ idx_s++;
+ if (idx_s == size_s) break;
+ val_s = small[idx_s];
+ idx_l = advanceUntil(large, (int32_t)idx_l, (int32_t)size_l, val_s);
+ if (idx_l == size_l) break;
+ val_l = large[idx_l];
+ }
+ }
+
+ return (int32_t)pos;
+}
+
+bool intersect_skewed_uint16_nonempty(const uint16_t *small, size_t size_s,
+ const uint16_t *large, size_t size_l) {
+ size_t idx_l = 0, idx_s = 0;
+
+ if (0 == size_s) {
+ return false;
+ }
+
+ uint16_t val_l = large[idx_l], val_s = small[idx_s];
+
+ while (true) {
+ if (val_l < val_s) {
+ idx_l = advanceUntil(large, (int32_t)idx_l, (int32_t)size_l, val_s);
+ if (idx_l == size_l) break;
+ val_l = large[idx_l];
+ } else if (val_s < val_l) {
+ idx_s++;
+ if (idx_s == size_s) break;
+ val_s = small[idx_s];
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Generic intersection function.
+ */
+int32_t intersect_uint16(const uint16_t *A, const size_t lenA,
+ const uint16_t *B, const size_t lenB, uint16_t *out) {
+ const uint16_t *initout = out;
+ if (lenA == 0 || lenB == 0) return 0;
+ const uint16_t *endA = A + lenA;
+ const uint16_t *endB = B + lenB;
+
+ while (1) {
+ while (*A < *B) {
+ SKIP_FIRST_COMPARE:
+ if (++A == endA) return (int32_t)(out - initout);
+ }
+ while (*A > *B) {
+ if (++B == endB) return (int32_t)(out - initout);
+ }
+ if (*A == *B) {
+ *out++ = *A;
+ if (++A == endA || ++B == endB) return (int32_t)(out - initout);
+ } else {
+ goto SKIP_FIRST_COMPARE;
+ }
+ }
+ return (int32_t)(out - initout); // NOTREACHED
+}
+
+int32_t intersect_uint16_cardinality(const uint16_t *A, const size_t lenA,
+ const uint16_t *B, const size_t lenB) {
+ int32_t answer = 0;
+ if (lenA == 0 || lenB == 0) return 0;
+ const uint16_t *endA = A + lenA;
+ const uint16_t *endB = B + lenB;
+
+ while (1) {
+ while (*A < *B) {
+ SKIP_FIRST_COMPARE:
+ if (++A == endA) return answer;
+ }
+ while (*A > *B) {
+ if (++B == endB) return answer;
+ }
+ if (*A == *B) {
+ ++answer;
+ if (++A == endA || ++B == endB) return answer;
+ } else {
+ goto SKIP_FIRST_COMPARE;
+ }
+ }
+ return answer; // NOTREACHED
+}
+
+
+bool intersect_uint16_nonempty(const uint16_t *A, const size_t lenA,
+ const uint16_t *B, const size_t lenB) {
+ if (lenA == 0 || lenB == 0) return 0;
+ const uint16_t *endA = A + lenA;
+ const uint16_t *endB = B + lenB;
+
+ while (1) {
+ while (*A < *B) {
+ SKIP_FIRST_COMPARE:
+ if (++A == endA) return false;
+ }
+ while (*A > *B) {
+ if (++B == endB) return false;
+ }
+ if (*A == *B) {
+ return true;
+ } else {
+ goto SKIP_FIRST_COMPARE;
+ }
+ }
+ return false; // NOTREACHED
+}
+
+
+
+/**
+ * Generic intersection function.
+ */
+size_t intersection_uint32(const uint32_t *A, const size_t lenA,
+ const uint32_t *B, const size_t lenB,
+ uint32_t *out) {
+ const uint32_t *initout = out;
+ if (lenA == 0 || lenB == 0) return 0;
+ const uint32_t *endA = A + lenA;
+ const uint32_t *endB = B + lenB;
+
+ while (1) {
+ while (*A < *B) {
+ SKIP_FIRST_COMPARE:
+ if (++A == endA) return (out - initout);
+ }
+ while (*A > *B) {
+ if (++B == endB) return (out - initout);
+ }
+ if (*A == *B) {
+ *out++ = *A;
+ if (++A == endA || ++B == endB) return (out - initout);
+ } else {
+ goto SKIP_FIRST_COMPARE;
+ }
+ }
+ return (out - initout); // NOTREACHED
+}
+
+size_t intersection_uint32_card(const uint32_t *A, const size_t lenA,
+ const uint32_t *B, const size_t lenB) {
+ if (lenA == 0 || lenB == 0) return 0;
+ size_t card = 0;
+ const uint32_t *endA = A + lenA;
+ const uint32_t *endB = B + lenB;
+
+ while (1) {
+ while (*A < *B) {
+ SKIP_FIRST_COMPARE:
+ if (++A == endA) return card;
+ }
+ while (*A > *B) {
+ if (++B == endB) return card;
+ }
+ if (*A == *B) {
+ card++;
+ if (++A == endA || ++B == endB) return card;
+ } else {
+ goto SKIP_FIRST_COMPARE;
+ }
+ }
+ return card; // NOTREACHED
+}
+
+// can one vectorize the computation of the union? (Update: Yes! See
+// union_vector16).
+
+size_t union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
+ size_t size_2, uint16_t *buffer) {
+ size_t pos = 0, idx_1 = 0, idx_2 = 0;
+
+ if (0 == size_2) {
+ memmove(buffer, set_1, size_1 * sizeof(uint16_t));
+ return size_1;
+ }
+ if (0 == size_1) {
+ memmove(buffer, set_2, size_2 * sizeof(uint16_t));
+ return size_2;
+ }
+
+ uint16_t val_1 = set_1[idx_1], val_2 = set_2[idx_2];
+
+ while (true) {
+ if (val_1 < val_2) {
+ buffer[pos++] = val_1;
+ ++idx_1;
+ if (idx_1 >= size_1) break;
+ val_1 = set_1[idx_1];
+ } else if (val_2 < val_1) {
+ buffer[pos++] = val_2;
+ ++idx_2;
+ if (idx_2 >= size_2) break;
+ val_2 = set_2[idx_2];
+ } else {
+ buffer[pos++] = val_1;
+ ++idx_1;
+ ++idx_2;
+ if (idx_1 >= size_1 || idx_2 >= size_2) break;
+ val_1 = set_1[idx_1];
+ val_2 = set_2[idx_2];
+ }
+ }
+
+ if (idx_1 < size_1) {
+ const size_t n_elems = size_1 - idx_1;
+ memmove(buffer + pos, set_1 + idx_1, n_elems * sizeof(uint16_t));
+ pos += n_elems;
+ } else if (idx_2 < size_2) {
+ const size_t n_elems = size_2 - idx_2;
+ memmove(buffer + pos, set_2 + idx_2, n_elems * sizeof(uint16_t));
+ pos += n_elems;
+ }
+
+ return pos;
+}
+
+int difference_uint16(const uint16_t *a1, int length1, const uint16_t *a2,
+ int length2, uint16_t *a_out) {
+ int out_card = 0;
+ int k1 = 0, k2 = 0;
+ if (length1 == 0) return 0;
+ if (length2 == 0) {
+ if (a1 != a_out) memcpy(a_out, a1, sizeof(uint16_t) * length1);
+ return length1;
+ }
+ uint16_t s1 = a1[k1];
+ uint16_t s2 = a2[k2];
+ while (true) {
+ if (s1 < s2) {
+ a_out[out_card++] = s1;
+ ++k1;
+ if (k1 >= length1) {
+ break;
+ }
+ s1 = a1[k1];
+ } else if (s1 == s2) {
+ ++k1;
+ ++k2;
+ if (k1 >= length1) {
+ break;
+ }
+ if (k2 >= length2) {
+ memmove(a_out + out_card, a1 + k1,
+ sizeof(uint16_t) * (length1 - k1));
+ return out_card + length1 - k1;
+ }
+ s1 = a1[k1];
+ s2 = a2[k2];
+ } else { // if (val1>val2)
+ ++k2;
+ if (k2 >= length2) {
+ memmove(a_out + out_card, a1 + k1,
+ sizeof(uint16_t) * (length1 - k1));
+ return out_card + length1 - k1;
+ }
+ s2 = a2[k2];
+ }
+ }
+ return out_card;
+}
+
+int32_t xor_uint16(const uint16_t *array_1, int32_t card_1,
+ const uint16_t *array_2, int32_t card_2, uint16_t *out) {
+ int32_t pos1 = 0, pos2 = 0, pos_out = 0;
+ while (pos1 < card_1 && pos2 < card_2) {
+ const uint16_t v1 = array_1[pos1];
+ const uint16_t v2 = array_2[pos2];
+ if (v1 == v2) {
+ ++pos1;
+ ++pos2;
+ continue;
+ }
+ if (v1 < v2) {
+ out[pos_out++] = v1;
+ ++pos1;
+ } else {
+ out[pos_out++] = v2;
+ ++pos2;
+ }
+ }
+ if (pos1 < card_1) {
+ const size_t n_elems = card_1 - pos1;
+ memcpy(out + pos_out, array_1 + pos1, n_elems * sizeof(uint16_t));
+ pos_out += (int32_t)n_elems;
+ } else if (pos2 < card_2) {
+ const size_t n_elems = card_2 - pos2;
+ memcpy(out + pos_out, array_2 + pos2, n_elems * sizeof(uint16_t));
+ pos_out += (int32_t)n_elems;
+ }
+ return pos_out;
+}
+
+#ifdef USESSE4
+
+/***
+ * start of the SIMD 16-bit union code
+ *
+ */
+
+// Assuming that vInput1 and vInput2 are sorted, produces a sorted output going
+// from vecMin all the way to vecMax
+// developed originally for merge sort using SIMD instructions.
+// Standard merge. See, e.g., Inoue and Taura, SIMD- and Cache-Friendly
+// Algorithm for Sorting an Array of Structures
+static inline void sse_merge(const __m128i *vInput1,
+ const __m128i *vInput2, // input 1 & 2
+ __m128i *vecMin, __m128i *vecMax) { // output
+ __m128i vecTmp;
+ vecTmp = _mm_min_epu16(*vInput1, *vInput2);
+ *vecMax = _mm_max_epu16(*vInput1, *vInput2);
+ vecTmp = _mm_alignr_epi8(vecTmp, vecTmp, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ vecTmp = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ vecTmp = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ vecTmp = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ vecTmp = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ vecTmp = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ vecTmp = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+ *vecMin = _mm_min_epu16(vecTmp, *vecMax);
+ *vecMax = _mm_max_epu16(vecTmp, *vecMax);
+ *vecMin = _mm_alignr_epi8(*vecMin, *vecMin, 2);
+}
+
+// used by store_unique, generated by simdunion.py
+static uint8_t uniqshuf[] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
+ 0xc, 0xd, 0xe, 0xf, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0xa, 0xb,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0xa, 0xb, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0xa, 0xb, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0xa, 0xb,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7,
+ 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x8, 0x9, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8, 0x9, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x6, 0x7, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x6, 0x7, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x6, 0x7, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0xc, 0xd, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0xc, 0xd,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x8, 0x9,
+ 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x8, 0x9, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7,
+ 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7, 0xa, 0xb, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7,
+ 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6, 0x7, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xa, 0xb,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0xa, 0xb, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xa, 0xb, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x6, 0x7, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7,
+ 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x6, 0x7, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x8, 0x9,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x8, 0x9,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x8, 0x9, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x6, 0x7, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x6, 0x7, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x6, 0x7, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0xe, 0xf, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0xe, 0xf,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9,
+ 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8, 0x9, 0xa, 0xb,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0xa, 0xb,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7,
+ 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0xa, 0xb, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0xa, 0xb,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0xa, 0xb,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7, 0x8, 0x9, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0x8, 0x9,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x8, 0x9,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x8, 0x9, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x6, 0x7, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6, 0x7, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xc, 0xd,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0xc, 0xd, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xc, 0xd, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9,
+ 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xa, 0xb,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x8, 0x9,
+ 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x8, 0x9,
+ 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x8, 0x9, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x6, 0x7, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7, 0xa, 0xb, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x6, 0x7, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x6, 0x7, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7, 0xa, 0xb, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0xa, 0xb,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0xa, 0xb, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0xa, 0xb, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0xa, 0xb,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xa, 0xb, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x6, 0x7,
+ 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x8, 0x9,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5,
+ 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x4, 0x5, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8, 0x9, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5,
+ 0x6, 0x7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x4, 0x5, 0x6, 0x7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3, 0x6, 0x7, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0x6, 0x7,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x6, 0x7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x6, 0x7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x2, 0x3, 0x4, 0x5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0x4, 0x5, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4, 0x5, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x0, 0x1, 0x2, 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x2, 0x3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x1, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF};
+
+// write vector new, while omitting repeated values assuming that previously
+// written vector was "old"
+static inline int store_unique(__m128i old, __m128i newval, uint16_t *output) {
+ __m128i vecTmp = _mm_alignr_epi8(newval, old, 16 - 2);
+ // lots of high latency instructions follow (optimize?)
+ int M = _mm_movemask_epi8(
+ _mm_packs_epi16(_mm_cmpeq_epi16(vecTmp, newval), _mm_setzero_si128()));
+ int numberofnewvalues = 8 - _mm_popcnt_u32(M);
+ __m128i key = _mm_lddqu_si128((const __m128i *)uniqshuf + M);
+ __m128i val = _mm_shuffle_epi8(newval, key);
+ _mm_storeu_si128((__m128i *)output, val);
+ return numberofnewvalues;
+}
+
+// working in-place, this function overwrites the repeated values
+// could be avoided?
+static inline uint32_t unique(uint16_t *out, uint32_t len) {
+ uint32_t pos = 1;
+ for (uint32_t i = 1; i < len; ++i) {
+ if (out[i] != out[i - 1]) {
+ out[pos++] = out[i];
+ }
+ }
+ return pos;
+}
+
+// use with qsort, could be avoided
+static int uint16_compare(const void *a, const void *b) {
+ return (*(uint16_t *)a - *(uint16_t *)b);
+}
+
+// a one-pass SSE union algorithm
+// This function may not be safe if array1 == output or array2 == output.
+uint32_t union_vector16(const uint16_t *__restrict__ array1, uint32_t length1,
+ const uint16_t *__restrict__ array2, uint32_t length2,
+ uint16_t *__restrict__ output) {
+ if ((length1 < 8) || (length2 < 8)) {
+ return (uint32_t)union_uint16(array1, length1, array2, length2, output);
+ }
+ __m128i vA, vB, V, vecMin, vecMax;
+ __m128i laststore;
+ uint16_t *initoutput = output;
+ uint32_t len1 = length1 / 8;
+ uint32_t len2 = length2 / 8;
+ uint32_t pos1 = 0;
+ uint32_t pos2 = 0;
+ // we start the machine
+ vA = _mm_lddqu_si128((const __m128i *)array1 + pos1);
+ pos1++;
+ vB = _mm_lddqu_si128((const __m128i *)array2 + pos2);
+ pos2++;
+ sse_merge(&vA, &vB, &vecMin, &vecMax);
+ laststore = _mm_set1_epi16(-1);
+ output += store_unique(laststore, vecMin, output);
+ laststore = vecMin;
+ if ((pos1 < len1) && (pos2 < len2)) {
+ uint16_t curA, curB;
+ curA = array1[8 * pos1];
+ curB = array2[8 * pos2];
+ while (true) {
+ if (curA <= curB) {
+ V = _mm_lddqu_si128((const __m128i *)array1 + pos1);
+ pos1++;
+ if (pos1 < len1) {
+ curA = array1[8 * pos1];
+ } else {
+ break;
+ }
+ } else {
+ V = _mm_lddqu_si128((const __m128i *)array2 + pos2);
+ pos2++;
+ if (pos2 < len2) {
+ curB = array2[8 * pos2];
+ } else {
+ break;
+ }
+ }
+ sse_merge(&V, &vecMax, &vecMin, &vecMax);
+ output += store_unique(laststore, vecMin, output);
+ laststore = vecMin;
+ }
+ sse_merge(&V, &vecMax, &vecMin, &vecMax);
+ output += store_unique(laststore, vecMin, output);
+ laststore = vecMin;
+ }
+ // we finish the rest off using a scalar algorithm
+ // could be improved?
+ //
+ // copy the small end on a tmp buffer
+ uint32_t len = (uint32_t)(output - initoutput);
+ uint16_t buffer[16];
+ uint32_t leftoversize = store_unique(laststore, vecMax, buffer);
+ if (pos1 == len1) {
+ memcpy(buffer + leftoversize, array1 + 8 * pos1,
+ (length1 - 8 * len1) * sizeof(uint16_t));
+ leftoversize += length1 - 8 * len1;
+ qsort(buffer, leftoversize, sizeof(uint16_t), uint16_compare);
+
+ leftoversize = unique(buffer, leftoversize);
+ len += (uint32_t)union_uint16(buffer, leftoversize, array2 + 8 * pos2,
+ length2 - 8 * pos2, output);
+ } else {
+ memcpy(buffer + leftoversize, array2 + 8 * pos2,
+ (length2 - 8 * len2) * sizeof(uint16_t));
+ leftoversize += length2 - 8 * len2;
+ qsort(buffer, leftoversize, sizeof(uint16_t), uint16_compare);
+ leftoversize = unique(buffer, leftoversize);
+ len += (uint32_t)union_uint16(buffer, leftoversize, array1 + 8 * pos1,
+ length1 - 8 * pos1, output);
+ }
+ return len;
+}
+
+/**
+ * End of the SIMD 16-bit union code
+ *
+ */
+
+/**
+ * Start of SIMD 16-bit XOR code
+ */
+
+// write vector new, while omitting repeated values assuming that previously
+// written vector was "old"
+static inline int store_unique_xor(__m128i old, __m128i newval,
+ uint16_t *output) {
+ __m128i vecTmp1 = _mm_alignr_epi8(newval, old, 16 - 4);
+ __m128i vecTmp2 = _mm_alignr_epi8(newval, old, 16 - 2);
+ __m128i equalleft = _mm_cmpeq_epi16(vecTmp2, vecTmp1);
+ __m128i equalright = _mm_cmpeq_epi16(vecTmp2, newval);
+ __m128i equalleftoright = _mm_or_si128(equalleft, equalright);
+ int M = _mm_movemask_epi8(
+ _mm_packs_epi16(equalleftoright, _mm_setzero_si128()));
+ int numberofnewvalues = 8 - _mm_popcnt_u32(M);
+ __m128i key = _mm_lddqu_si128((const __m128i *)uniqshuf + M);
+ __m128i val = _mm_shuffle_epi8(vecTmp2, key);
+ _mm_storeu_si128((__m128i *)output, val);
+ return numberofnewvalues;
+}
+
+// working in-place, this function overwrites the repeated values
+// could be avoided? Warning: assumes len > 0
+static inline uint32_t unique_xor(uint16_t *out, uint32_t len) {
+ uint32_t pos = 1;
+ for (uint32_t i = 1; i < len; ++i) {
+ if (out[i] != out[i - 1]) {
+ out[pos++] = out[i];
+ } else
+ pos--; // if it is identical to previous, delete it
+ }
+ return pos;
+}
+
+// a one-pass SSE xor algorithm
+uint32_t xor_vector16(const uint16_t *__restrict__ array1, uint32_t length1,
+ const uint16_t *__restrict__ array2, uint32_t length2,
+ uint16_t *__restrict__ output) {
+ if ((length1 < 8) || (length2 < 8)) {
+ return xor_uint16(array1, length1, array2, length2, output);
+ }
+ __m128i vA, vB, V, vecMin, vecMax;
+ __m128i laststore;
+ uint16_t *initoutput = output;
+ uint32_t len1 = length1 / 8;
+ uint32_t len2 = length2 / 8;
+ uint32_t pos1 = 0;
+ uint32_t pos2 = 0;
+ // we start the machine
+ vA = _mm_lddqu_si128((const __m128i *)array1 + pos1);
+ pos1++;
+ vB = _mm_lddqu_si128((const __m128i *)array2 + pos2);
+ pos2++;
+ sse_merge(&vA, &vB, &vecMin, &vecMax);
+ laststore = _mm_set1_epi16(-1);
+ uint16_t buffer[17];
+ output += store_unique_xor(laststore, vecMin, output);
+
+ laststore = vecMin;
+ if ((pos1 < len1) && (pos2 < len2)) {
+ uint16_t curA, curB;
+ curA = array1[8 * pos1];
+ curB = array2[8 * pos2];
+ while (true) {
+ if (curA <= curB) {
+ V = _mm_lddqu_si128((const __m128i *)array1 + pos1);
+ pos1++;
+ if (pos1 < len1) {
+ curA = array1[8 * pos1];
+ } else {
+ break;
+ }
+ } else {
+ V = _mm_lddqu_si128((const __m128i *)array2 + pos2);
+ pos2++;
+ if (pos2 < len2) {
+ curB = array2[8 * pos2];
+ } else {
+ break;
+ }
+ }
+ sse_merge(&V, &vecMax, &vecMin, &vecMax);
+ // conditionally stores the last value of laststore as well as all
+ // but the
+ // last value of vecMin
+ output += store_unique_xor(laststore, vecMin, output);
+ laststore = vecMin;
+ }
+ sse_merge(&V, &vecMax, &vecMin, &vecMax);
+ // conditionally stores the last value of laststore as well as all but
+ // the
+ // last value of vecMin
+ output += store_unique_xor(laststore, vecMin, output);
+ laststore = vecMin;
+ }
+ uint32_t len = (uint32_t)(output - initoutput);
+
+ // we finish the rest off using a scalar algorithm
+ // could be improved?
+ // conditionally stores the last value of laststore as well as all but the
+ // last value of vecMax,
+ // we store to "buffer"
+ int leftoversize = store_unique_xor(laststore, vecMax, buffer);
+ uint16_t vec7 = _mm_extract_epi16(vecMax, 7);
+ uint16_t vec6 = _mm_extract_epi16(vecMax, 6);
+ if (vec7 != vec6) buffer[leftoversize++] = vec7;
+ if (pos1 == len1) {
+ memcpy(buffer + leftoversize, array1 + 8 * pos1,
+ (length1 - 8 * len1) * sizeof(uint16_t));
+ leftoversize += length1 - 8 * len1;
+ if (leftoversize == 0) { // trivial case
+ memcpy(output, array2 + 8 * pos2,
+ (length2 - 8 * pos2) * sizeof(uint16_t));
+ len += (length2 - 8 * pos2);
+ } else {
+ qsort(buffer, leftoversize, sizeof(uint16_t), uint16_compare);
+ leftoversize = unique_xor(buffer, leftoversize);
+ len += xor_uint16(buffer, leftoversize, array2 + 8 * pos2,
+ length2 - 8 * pos2, output);
+ }
+ } else {
+ memcpy(buffer + leftoversize, array2 + 8 * pos2,
+ (length2 - 8 * len2) * sizeof(uint16_t));
+ leftoversize += length2 - 8 * len2;
+ if (leftoversize == 0) { // trivial case
+ memcpy(output, array1 + 8 * pos1,
+ (length1 - 8 * pos1) * sizeof(uint16_t));
+ len += (length1 - 8 * pos1);
+ } else {
+ qsort(buffer, leftoversize, sizeof(uint16_t), uint16_compare);
+ leftoversize = unique_xor(buffer, leftoversize);
+ len += xor_uint16(buffer, leftoversize, array1 + 8 * pos1,
+ length1 - 8 * pos1, output);
+ }
+ }
+ return len;
+}
+
+/**
+ * End of SIMD 16-bit XOR code
+ */
+
+#endif // USESSE4
+
+size_t union_uint32(const uint32_t *set_1, size_t size_1, const uint32_t *set_2,
+ size_t size_2, uint32_t *buffer) {
+ size_t pos = 0, idx_1 = 0, idx_2 = 0;
+
+ if (0 == size_2) {
+ memmove(buffer, set_1, size_1 * sizeof(uint32_t));
+ return size_1;
+ }
+ if (0 == size_1) {
+ memmove(buffer, set_2, size_2 * sizeof(uint32_t));
+ return size_2;
+ }
+
+ uint32_t val_1 = set_1[idx_1], val_2 = set_2[idx_2];
+
+ while (true) {
+ if (val_1 < val_2) {
+ buffer[pos++] = val_1;
+ ++idx_1;
+ if (idx_1 >= size_1) break;
+ val_1 = set_1[idx_1];
+ } else if (val_2 < val_1) {
+ buffer[pos++] = val_2;
+ ++idx_2;
+ if (idx_2 >= size_2) break;
+ val_2 = set_2[idx_2];
+ } else {
+ buffer[pos++] = val_1;
+ ++idx_1;
+ ++idx_2;
+ if (idx_1 >= size_1 || idx_2 >= size_2) break;
+ val_1 = set_1[idx_1];
+ val_2 = set_2[idx_2];
+ }
+ }
+
+ if (idx_1 < size_1) {
+ const size_t n_elems = size_1 - idx_1;
+ memmove(buffer + pos, set_1 + idx_1, n_elems * sizeof(uint32_t));
+ pos += n_elems;
+ } else if (idx_2 < size_2) {
+ const size_t n_elems = size_2 - idx_2;
+ memmove(buffer + pos, set_2 + idx_2, n_elems * sizeof(uint32_t));
+ pos += n_elems;
+ }
+
+ return pos;
+}
+
+size_t union_uint32_card(const uint32_t *set_1, size_t size_1,
+ const uint32_t *set_2, size_t size_2) {
+ size_t pos = 0, idx_1 = 0, idx_2 = 0;
+
+ if (0 == size_2) {
+ return size_1;
+ }
+ if (0 == size_1) {
+ return size_2;
+ }
+
+ uint32_t val_1 = set_1[idx_1], val_2 = set_2[idx_2];
+
+ while (true) {
+ if (val_1 < val_2) {
+ ++idx_1;
+ ++pos;
+ if (idx_1 >= size_1) break;
+ val_1 = set_1[idx_1];
+ } else if (val_2 < val_1) {
+ ++idx_2;
+ ++pos;
+ if (idx_2 >= size_2) break;
+ val_2 = set_2[idx_2];
+ } else {
+ ++idx_1;
+ ++idx_2;
+ ++pos;
+ if (idx_1 >= size_1 || idx_2 >= size_2) break;
+ val_1 = set_1[idx_1];
+ val_2 = set_2[idx_2];
+ }
+ }
+
+ if (idx_1 < size_1) {
+ const size_t n_elems = size_1 - idx_1;
+ pos += n_elems;
+ } else if (idx_2 < size_2) {
+ const size_t n_elems = size_2 - idx_2;
+ pos += n_elems;
+ }
+ return pos;
+}
+
+
+
+size_t fast_union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
+ size_t size_2, uint16_t *buffer) {
+#ifdef ROARING_VECTOR_OPERATIONS_ENABLED
+ // compute union with smallest array first
+ if (size_1 < size_2) {
+ return union_vector16(set_1, (uint32_t)size_1,
+ set_2, (uint32_t)size_2, buffer);
+ } else {
+ return union_vector16(set_2, (uint32_t)size_2,
+ set_1, (uint32_t)size_1, buffer);
+ }
+#else
+ // compute union with smallest array first
+ if (size_1 < size_2) {
+ return union_uint16(
+ set_1, size_1, set_2, size_2, buffer);
+ } else {
+ return union_uint16(
+ set_2, size_2, set_1, size_1, buffer);
+ }
+#endif
+}
+
+bool memequals(const void *s1, const void *s2, size_t n) {
+ if (n == 0) {
+ return true;
+ }
+#ifdef USEAVX
+ const uint8_t *ptr1 = (const uint8_t *)s1;
+ const uint8_t *ptr2 = (const uint8_t *)s2;
+ const uint8_t *end1 = ptr1 + n;
+ const uint8_t *end8 = ptr1 + n/8*8;
+ const uint8_t *end32 = ptr1 + n/32*32;
+
+ while (ptr1 < end32) {
+ __m256i r1 = _mm256_loadu_si256((const __m256i*)ptr1);
+ __m256i r2 = _mm256_loadu_si256((const __m256i*)ptr2);
+ int mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(r1, r2));
+ if ((uint32_t)mask != UINT32_MAX) {
+ return false;
+ }
+ ptr1 += 32;
+ ptr2 += 32;
+ }
+
+ while (ptr1 < end8) {
+ uint64_t v1 = *((const uint64_t*)ptr1);
+ uint64_t v2 = *((const uint64_t*)ptr2);
+ if (v1 != v2) {
+ return false;
+ }
+ ptr1 += 8;
+ ptr2 += 8;
+ }
+
+ while (ptr1 < end1) {
+ if (*ptr1 != *ptr2) {
+ return false;
+ }
+ ptr1++;
+ ptr2++;
+ }
+
+ return true;
+#else
+ return memcmp(s1, s2, n) == 0;
+#endif
+}
+/* end file src/array_util.c */
+/* begin file src/bitset_util.c */
+#include
+#include
+#include
+#include
+#include
+
+
+#ifdef IS_X64
+static uint8_t lengthTable[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
+#endif
+
+#ifdef USEAVX
+ALIGNED(32)
+static uint32_t vecDecodeTable[256][8] = {
+ {0, 0, 0, 0, 0, 0, 0, 0}, /* 0x00 (00000000) */
+ {1, 0, 0, 0, 0, 0, 0, 0}, /* 0x01 (00000001) */
+ {2, 0, 0, 0, 0, 0, 0, 0}, /* 0x02 (00000010) */
+ {1, 2, 0, 0, 0, 0, 0, 0}, /* 0x03 (00000011) */
+ {3, 0, 0, 0, 0, 0, 0, 0}, /* 0x04 (00000100) */
+ {1, 3, 0, 0, 0, 0, 0, 0}, /* 0x05 (00000101) */
+ {2, 3, 0, 0, 0, 0, 0, 0}, /* 0x06 (00000110) */
+ {1, 2, 3, 0, 0, 0, 0, 0}, /* 0x07 (00000111) */
+ {4, 0, 0, 0, 0, 0, 0, 0}, /* 0x08 (00001000) */
+ {1, 4, 0, 0, 0, 0, 0, 0}, /* 0x09 (00001001) */
+ {2, 4, 0, 0, 0, 0, 0, 0}, /* 0x0A (00001010) */
+ {1, 2, 4, 0, 0, 0, 0, 0}, /* 0x0B (00001011) */
+ {3, 4, 0, 0, 0, 0, 0, 0}, /* 0x0C (00001100) */
+ {1, 3, 4, 0, 0, 0, 0, 0}, /* 0x0D (00001101) */
+ {2, 3, 4, 0, 0, 0, 0, 0}, /* 0x0E (00001110) */
+ {1, 2, 3, 4, 0, 0, 0, 0}, /* 0x0F (00001111) */
+ {5, 0, 0, 0, 0, 0, 0, 0}, /* 0x10 (00010000) */
+ {1, 5, 0, 0, 0, 0, 0, 0}, /* 0x11 (00010001) */
+ {2, 5, 0, 0, 0, 0, 0, 0}, /* 0x12 (00010010) */
+ {1, 2, 5, 0, 0, 0, 0, 0}, /* 0x13 (00010011) */
+ {3, 5, 0, 0, 0, 0, 0, 0}, /* 0x14 (00010100) */
+ {1, 3, 5, 0, 0, 0, 0, 0}, /* 0x15 (00010101) */
+ {2, 3, 5, 0, 0, 0, 0, 0}, /* 0x16 (00010110) */
+ {1, 2, 3, 5, 0, 0, 0, 0}, /* 0x17 (00010111) */
+ {4, 5, 0, 0, 0, 0, 0, 0}, /* 0x18 (00011000) */
+ {1, 4, 5, 0, 0, 0, 0, 0}, /* 0x19 (00011001) */
+ {2, 4, 5, 0, 0, 0, 0, 0}, /* 0x1A (00011010) */
+ {1, 2, 4, 5, 0, 0, 0, 0}, /* 0x1B (00011011) */
+ {3, 4, 5, 0, 0, 0, 0, 0}, /* 0x1C (00011100) */
+ {1, 3, 4, 5, 0, 0, 0, 0}, /* 0x1D (00011101) */
+ {2, 3, 4, 5, 0, 0, 0, 0}, /* 0x1E (00011110) */
+ {1, 2, 3, 4, 5, 0, 0, 0}, /* 0x1F (00011111) */
+ {6, 0, 0, 0, 0, 0, 0, 0}, /* 0x20 (00100000) */
+ {1, 6, 0, 0, 0, 0, 0, 0}, /* 0x21 (00100001) */
+ {2, 6, 0, 0, 0, 0, 0, 0}, /* 0x22 (00100010) */
+ {1, 2, 6, 0, 0, 0, 0, 0}, /* 0x23 (00100011) */
+ {3, 6, 0, 0, 0, 0, 0, 0}, /* 0x24 (00100100) */
+ {1, 3, 6, 0, 0, 0, 0, 0}, /* 0x25 (00100101) */
+ {2, 3, 6, 0, 0, 0, 0, 0}, /* 0x26 (00100110) */
+ {1, 2, 3, 6, 0, 0, 0, 0}, /* 0x27 (00100111) */
+ {4, 6, 0, 0, 0, 0, 0, 0}, /* 0x28 (00101000) */
+ {1, 4, 6, 0, 0, 0, 0, 0}, /* 0x29 (00101001) */
+ {2, 4, 6, 0, 0, 0, 0, 0}, /* 0x2A (00101010) */
+ {1, 2, 4, 6, 0, 0, 0, 0}, /* 0x2B (00101011) */
+ {3, 4, 6, 0, 0, 0, 0, 0}, /* 0x2C (00101100) */
+ {1, 3, 4, 6, 0, 0, 0, 0}, /* 0x2D (00101101) */
+ {2, 3, 4, 6, 0, 0, 0, 0}, /* 0x2E (00101110) */
+ {1, 2, 3, 4, 6, 0, 0, 0}, /* 0x2F (00101111) */
+ {5, 6, 0, 0, 0, 0, 0, 0}, /* 0x30 (00110000) */
+ {1, 5, 6, 0, 0, 0, 0, 0}, /* 0x31 (00110001) */
+ {2, 5, 6, 0, 0, 0, 0, 0}, /* 0x32 (00110010) */
+ {1, 2, 5, 6, 0, 0, 0, 0}, /* 0x33 (00110011) */
+ {3, 5, 6, 0, 0, 0, 0, 0}, /* 0x34 (00110100) */
+ {1, 3, 5, 6, 0, 0, 0, 0}, /* 0x35 (00110101) */
+ {2, 3, 5, 6, 0, 0, 0, 0}, /* 0x36 (00110110) */
+ {1, 2, 3, 5, 6, 0, 0, 0}, /* 0x37 (00110111) */
+ {4, 5, 6, 0, 0, 0, 0, 0}, /* 0x38 (00111000) */
+ {1, 4, 5, 6, 0, 0, 0, 0}, /* 0x39 (00111001) */
+ {2, 4, 5, 6, 0, 0, 0, 0}, /* 0x3A (00111010) */
+ {1, 2, 4, 5, 6, 0, 0, 0}, /* 0x3B (00111011) */
+ {3, 4, 5, 6, 0, 0, 0, 0}, /* 0x3C (00111100) */
+ {1, 3, 4, 5, 6, 0, 0, 0}, /* 0x3D (00111101) */
+ {2, 3, 4, 5, 6, 0, 0, 0}, /* 0x3E (00111110) */
+ {1, 2, 3, 4, 5, 6, 0, 0}, /* 0x3F (00111111) */
+ {7, 0, 0, 0, 0, 0, 0, 0}, /* 0x40 (01000000) */
+ {1, 7, 0, 0, 0, 0, 0, 0}, /* 0x41 (01000001) */
+ {2, 7, 0, 0, 0, 0, 0, 0}, /* 0x42 (01000010) */
+ {1, 2, 7, 0, 0, 0, 0, 0}, /* 0x43 (01000011) */
+ {3, 7, 0, 0, 0, 0, 0, 0}, /* 0x44 (01000100) */
+ {1, 3, 7, 0, 0, 0, 0, 0}, /* 0x45 (01000101) */
+ {2, 3, 7, 0, 0, 0, 0, 0}, /* 0x46 (01000110) */
+ {1, 2, 3, 7, 0, 0, 0, 0}, /* 0x47 (01000111) */
+ {4, 7, 0, 0, 0, 0, 0, 0}, /* 0x48 (01001000) */
+ {1, 4, 7, 0, 0, 0, 0, 0}, /* 0x49 (01001001) */
+ {2, 4, 7, 0, 0, 0, 0, 0}, /* 0x4A (01001010) */
+ {1, 2, 4, 7, 0, 0, 0, 0}, /* 0x4B (01001011) */
+ {3, 4, 7, 0, 0, 0, 0, 0}, /* 0x4C (01001100) */
+ {1, 3, 4, 7, 0, 0, 0, 0}, /* 0x4D (01001101) */
+ {2, 3, 4, 7, 0, 0, 0, 0}, /* 0x4E (01001110) */
+ {1, 2, 3, 4, 7, 0, 0, 0}, /* 0x4F (01001111) */
+ {5, 7, 0, 0, 0, 0, 0, 0}, /* 0x50 (01010000) */
+ {1, 5, 7, 0, 0, 0, 0, 0}, /* 0x51 (01010001) */
+ {2, 5, 7, 0, 0, 0, 0, 0}, /* 0x52 (01010010) */
+ {1, 2, 5, 7, 0, 0, 0, 0}, /* 0x53 (01010011) */
+ {3, 5, 7, 0, 0, 0, 0, 0}, /* 0x54 (01010100) */
+ {1, 3, 5, 7, 0, 0, 0, 0}, /* 0x55 (01010101) */
+ {2, 3, 5, 7, 0, 0, 0, 0}, /* 0x56 (01010110) */
+ {1, 2, 3, 5, 7, 0, 0, 0}, /* 0x57 (01010111) */
+ {4, 5, 7, 0, 0, 0, 0, 0}, /* 0x58 (01011000) */
+ {1, 4, 5, 7, 0, 0, 0, 0}, /* 0x59 (01011001) */
+ {2, 4, 5, 7, 0, 0, 0, 0}, /* 0x5A (01011010) */
+ {1, 2, 4, 5, 7, 0, 0, 0}, /* 0x5B (01011011) */
+ {3, 4, 5, 7, 0, 0, 0, 0}, /* 0x5C (01011100) */
+ {1, 3, 4, 5, 7, 0, 0, 0}, /* 0x5D (01011101) */
+ {2, 3, 4, 5, 7, 0, 0, 0}, /* 0x5E (01011110) */
+ {1, 2, 3, 4, 5, 7, 0, 0}, /* 0x5F (01011111) */
+ {6, 7, 0, 0, 0, 0, 0, 0}, /* 0x60 (01100000) */
+ {1, 6, 7, 0, 0, 0, 0, 0}, /* 0x61 (01100001) */
+ {2, 6, 7, 0, 0, 0, 0, 0}, /* 0x62 (01100010) */
+ {1, 2, 6, 7, 0, 0, 0, 0}, /* 0x63 (01100011) */
+ {3, 6, 7, 0, 0, 0, 0, 0}, /* 0x64 (01100100) */
+ {1, 3, 6, 7, 0, 0, 0, 0}, /* 0x65 (01100101) */
+ {2, 3, 6, 7, 0, 0, 0, 0}, /* 0x66 (01100110) */
+ {1, 2, 3, 6, 7, 0, 0, 0}, /* 0x67 (01100111) */
+ {4, 6, 7, 0, 0, 0, 0, 0}, /* 0x68 (01101000) */
+ {1, 4, 6, 7, 0, 0, 0, 0}, /* 0x69 (01101001) */
+ {2, 4, 6, 7, 0, 0, 0, 0}, /* 0x6A (01101010) */
+ {1, 2, 4, 6, 7, 0, 0, 0}, /* 0x6B (01101011) */
+ {3, 4, 6, 7, 0, 0, 0, 0}, /* 0x6C (01101100) */
+ {1, 3, 4, 6, 7, 0, 0, 0}, /* 0x6D (01101101) */
+ {2, 3, 4, 6, 7, 0, 0, 0}, /* 0x6E (01101110) */
+ {1, 2, 3, 4, 6, 7, 0, 0}, /* 0x6F (01101111) */
+ {5, 6, 7, 0, 0, 0, 0, 0}, /* 0x70 (01110000) */
+ {1, 5, 6, 7, 0, 0, 0, 0}, /* 0x71 (01110001) */
+ {2, 5, 6, 7, 0, 0, 0, 0}, /* 0x72 (01110010) */
+ {1, 2, 5, 6, 7, 0, 0, 0}, /* 0x73 (01110011) */
+ {3, 5, 6, 7, 0, 0, 0, 0}, /* 0x74 (01110100) */
+ {1, 3, 5, 6, 7, 0, 0, 0}, /* 0x75 (01110101) */
+ {2, 3, 5, 6, 7, 0, 0, 0}, /* 0x76 (01110110) */
+ {1, 2, 3, 5, 6, 7, 0, 0}, /* 0x77 (01110111) */
+ {4, 5, 6, 7, 0, 0, 0, 0}, /* 0x78 (01111000) */
+ {1, 4, 5, 6, 7, 0, 0, 0}, /* 0x79 (01111001) */
+ {2, 4, 5, 6, 7, 0, 0, 0}, /* 0x7A (01111010) */
+ {1, 2, 4, 5, 6, 7, 0, 0}, /* 0x7B (01111011) */
+ {3, 4, 5, 6, 7, 0, 0, 0}, /* 0x7C (01111100) */
+ {1, 3, 4, 5, 6, 7, 0, 0}, /* 0x7D (01111101) */
+ {2, 3, 4, 5, 6, 7, 0, 0}, /* 0x7E (01111110) */
+ {1, 2, 3, 4, 5, 6, 7, 0}, /* 0x7F (01111111) */
+ {8, 0, 0, 0, 0, 0, 0, 0}, /* 0x80 (10000000) */
+ {1, 8, 0, 0, 0, 0, 0, 0}, /* 0x81 (10000001) */
+ {2, 8, 0, 0, 0, 0, 0, 0}, /* 0x82 (10000010) */
+ {1, 2, 8, 0, 0, 0, 0, 0}, /* 0x83 (10000011) */
+ {3, 8, 0, 0, 0, 0, 0, 0}, /* 0x84 (10000100) */
+ {1, 3, 8, 0, 0, 0, 0, 0}, /* 0x85 (10000101) */
+ {2, 3, 8, 0, 0, 0, 0, 0}, /* 0x86 (10000110) */
+ {1, 2, 3, 8, 0, 0, 0, 0}, /* 0x87 (10000111) */
+ {4, 8, 0, 0, 0, 0, 0, 0}, /* 0x88 (10001000) */
+ {1, 4, 8, 0, 0, 0, 0, 0}, /* 0x89 (10001001) */
+ {2, 4, 8, 0, 0, 0, 0, 0}, /* 0x8A (10001010) */
+ {1, 2, 4, 8, 0, 0, 0, 0}, /* 0x8B (10001011) */
+ {3, 4, 8, 0, 0, 0, 0, 0}, /* 0x8C (10001100) */
+ {1, 3, 4, 8, 0, 0, 0, 0}, /* 0x8D (10001101) */
+ {2, 3, 4, 8, 0, 0, 0, 0}, /* 0x8E (10001110) */
+ {1, 2, 3, 4, 8, 0, 0, 0}, /* 0x8F (10001111) */
+ {5, 8, 0, 0, 0, 0, 0, 0}, /* 0x90 (10010000) */
+ {1, 5, 8, 0, 0, 0, 0, 0}, /* 0x91 (10010001) */
+ {2, 5, 8, 0, 0, 0, 0, 0}, /* 0x92 (10010010) */
+ {1, 2, 5, 8, 0, 0, 0, 0}, /* 0x93 (10010011) */
+ {3, 5, 8, 0, 0, 0, 0, 0}, /* 0x94 (10010100) */
+ {1, 3, 5, 8, 0, 0, 0, 0}, /* 0x95 (10010101) */
+ {2, 3, 5, 8, 0, 0, 0, 0}, /* 0x96 (10010110) */
+ {1, 2, 3, 5, 8, 0, 0, 0}, /* 0x97 (10010111) */
+ {4, 5, 8, 0, 0, 0, 0, 0}, /* 0x98 (10011000) */
+ {1, 4, 5, 8, 0, 0, 0, 0}, /* 0x99 (10011001) */
+ {2, 4, 5, 8, 0, 0, 0, 0}, /* 0x9A (10011010) */
+ {1, 2, 4, 5, 8, 0, 0, 0}, /* 0x9B (10011011) */
+ {3, 4, 5, 8, 0, 0, 0, 0}, /* 0x9C (10011100) */
+ {1, 3, 4, 5, 8, 0, 0, 0}, /* 0x9D (10011101) */
+ {2, 3, 4, 5, 8, 0, 0, 0}, /* 0x9E (10011110) */
+ {1, 2, 3, 4, 5, 8, 0, 0}, /* 0x9F (10011111) */
+ {6, 8, 0, 0, 0, 0, 0, 0}, /* 0xA0 (10100000) */
+ {1, 6, 8, 0, 0, 0, 0, 0}, /* 0xA1 (10100001) */
+ {2, 6, 8, 0, 0, 0, 0, 0}, /* 0xA2 (10100010) */
+ {1, 2, 6, 8, 0, 0, 0, 0}, /* 0xA3 (10100011) */
+ {3, 6, 8, 0, 0, 0, 0, 0}, /* 0xA4 (10100100) */
+ {1, 3, 6, 8, 0, 0, 0, 0}, /* 0xA5 (10100101) */
+ {2, 3, 6, 8, 0, 0, 0, 0}, /* 0xA6 (10100110) */
+ {1, 2, 3, 6, 8, 0, 0, 0}, /* 0xA7 (10100111) */
+ {4, 6, 8, 0, 0, 0, 0, 0}, /* 0xA8 (10101000) */
+ {1, 4, 6, 8, 0, 0, 0, 0}, /* 0xA9 (10101001) */
+ {2, 4, 6, 8, 0, 0, 0, 0}, /* 0xAA (10101010) */
+ {1, 2, 4, 6, 8, 0, 0, 0}, /* 0xAB (10101011) */
+ {3, 4, 6, 8, 0, 0, 0, 0}, /* 0xAC (10101100) */
+ {1, 3, 4, 6, 8, 0, 0, 0}, /* 0xAD (10101101) */
+ {2, 3, 4, 6, 8, 0, 0, 0}, /* 0xAE (10101110) */
+ {1, 2, 3, 4, 6, 8, 0, 0}, /* 0xAF (10101111) */
+ {5, 6, 8, 0, 0, 0, 0, 0}, /* 0xB0 (10110000) */
+ {1, 5, 6, 8, 0, 0, 0, 0}, /* 0xB1 (10110001) */
+ {2, 5, 6, 8, 0, 0, 0, 0}, /* 0xB2 (10110010) */
+ {1, 2, 5, 6, 8, 0, 0, 0}, /* 0xB3 (10110011) */
+ {3, 5, 6, 8, 0, 0, 0, 0}, /* 0xB4 (10110100) */
+ {1, 3, 5, 6, 8, 0, 0, 0}, /* 0xB5 (10110101) */
+ {2, 3, 5, 6, 8, 0, 0, 0}, /* 0xB6 (10110110) */
+ {1, 2, 3, 5, 6, 8, 0, 0}, /* 0xB7 (10110111) */
+ {4, 5, 6, 8, 0, 0, 0, 0}, /* 0xB8 (10111000) */
+ {1, 4, 5, 6, 8, 0, 0, 0}, /* 0xB9 (10111001) */
+ {2, 4, 5, 6, 8, 0, 0, 0}, /* 0xBA (10111010) */
+ {1, 2, 4, 5, 6, 8, 0, 0}, /* 0xBB (10111011) */
+ {3, 4, 5, 6, 8, 0, 0, 0}, /* 0xBC (10111100) */
+ {1, 3, 4, 5, 6, 8, 0, 0}, /* 0xBD (10111101) */
+ {2, 3, 4, 5, 6, 8, 0, 0}, /* 0xBE (10111110) */
+ {1, 2, 3, 4, 5, 6, 8, 0}, /* 0xBF (10111111) */
+ {7, 8, 0, 0, 0, 0, 0, 0}, /* 0xC0 (11000000) */
+ {1, 7, 8, 0, 0, 0, 0, 0}, /* 0xC1 (11000001) */
+ {2, 7, 8, 0, 0, 0, 0, 0}, /* 0xC2 (11000010) */
+ {1, 2, 7, 8, 0, 0, 0, 0}, /* 0xC3 (11000011) */
+ {3, 7, 8, 0, 0, 0, 0, 0}, /* 0xC4 (11000100) */
+ {1, 3, 7, 8, 0, 0, 0, 0}, /* 0xC5 (11000101) */
+ {2, 3, 7, 8, 0, 0, 0, 0}, /* 0xC6 (11000110) */
+ {1, 2, 3, 7, 8, 0, 0, 0}, /* 0xC7 (11000111) */
+ {4, 7, 8, 0, 0, 0, 0, 0}, /* 0xC8 (11001000) */
+ {1, 4, 7, 8, 0, 0, 0, 0}, /* 0xC9 (11001001) */
+ {2, 4, 7, 8, 0, 0, 0, 0}, /* 0xCA (11001010) */
+ {1, 2, 4, 7, 8, 0, 0, 0}, /* 0xCB (11001011) */
+ {3, 4, 7, 8, 0, 0, 0, 0}, /* 0xCC (11001100) */
+ {1, 3, 4, 7, 8, 0, 0, 0}, /* 0xCD (11001101) */
+ {2, 3, 4, 7, 8, 0, 0, 0}, /* 0xCE (11001110) */
+ {1, 2, 3, 4, 7, 8, 0, 0}, /* 0xCF (11001111) */
+ {5, 7, 8, 0, 0, 0, 0, 0}, /* 0xD0 (11010000) */
+ {1, 5, 7, 8, 0, 0, 0, 0}, /* 0xD1 (11010001) */
+ {2, 5, 7, 8, 0, 0, 0, 0}, /* 0xD2 (11010010) */
+ {1, 2, 5, 7, 8, 0, 0, 0}, /* 0xD3 (11010011) */
+ {3, 5, 7, 8, 0, 0, 0, 0}, /* 0xD4 (11010100) */
+ {1, 3, 5, 7, 8, 0, 0, 0}, /* 0xD5 (11010101) */
+ {2, 3, 5, 7, 8, 0, 0, 0}, /* 0xD6 (11010110) */
+ {1, 2, 3, 5, 7, 8, 0, 0}, /* 0xD7 (11010111) */
+ {4, 5, 7, 8, 0, 0, 0, 0}, /* 0xD8 (11011000) */
+ {1, 4, 5, 7, 8, 0, 0, 0}, /* 0xD9 (11011001) */
+ {2, 4, 5, 7, 8, 0, 0, 0}, /* 0xDA (11011010) */
+ {1, 2, 4, 5, 7, 8, 0, 0}, /* 0xDB (11011011) */
+ {3, 4, 5, 7, 8, 0, 0, 0}, /* 0xDC (11011100) */
+ {1, 3, 4, 5, 7, 8, 0, 0}, /* 0xDD (11011101) */
+ {2, 3, 4, 5, 7, 8, 0, 0}, /* 0xDE (11011110) */
+ {1, 2, 3, 4, 5, 7, 8, 0}, /* 0xDF (11011111) */
+ {6, 7, 8, 0, 0, 0, 0, 0}, /* 0xE0 (11100000) */
+ {1, 6, 7, 8, 0, 0, 0, 0}, /* 0xE1 (11100001) */
+ {2, 6, 7, 8, 0, 0, 0, 0}, /* 0xE2 (11100010) */
+ {1, 2, 6, 7, 8, 0, 0, 0}, /* 0xE3 (11100011) */
+ {3, 6, 7, 8, 0, 0, 0, 0}, /* 0xE4 (11100100) */
+ {1, 3, 6, 7, 8, 0, 0, 0}, /* 0xE5 (11100101) */
+ {2, 3, 6, 7, 8, 0, 0, 0}, /* 0xE6 (11100110) */
+ {1, 2, 3, 6, 7, 8, 0, 0}, /* 0xE7 (11100111) */
+ {4, 6, 7, 8, 0, 0, 0, 0}, /* 0xE8 (11101000) */
+ {1, 4, 6, 7, 8, 0, 0, 0}, /* 0xE9 (11101001) */
+ {2, 4, 6, 7, 8, 0, 0, 0}, /* 0xEA (11101010) */
+ {1, 2, 4, 6, 7, 8, 0, 0}, /* 0xEB (11101011) */
+ {3, 4, 6, 7, 8, 0, 0, 0}, /* 0xEC (11101100) */
+ {1, 3, 4, 6, 7, 8, 0, 0}, /* 0xED (11101101) */
+ {2, 3, 4, 6, 7, 8, 0, 0}, /* 0xEE (11101110) */
+ {1, 2, 3, 4, 6, 7, 8, 0}, /* 0xEF (11101111) */
+ {5, 6, 7, 8, 0, 0, 0, 0}, /* 0xF0 (11110000) */
+ {1, 5, 6, 7, 8, 0, 0, 0}, /* 0xF1 (11110001) */
+ {2, 5, 6, 7, 8, 0, 0, 0}, /* 0xF2 (11110010) */
+ {1, 2, 5, 6, 7, 8, 0, 0}, /* 0xF3 (11110011) */
+ {3, 5, 6, 7, 8, 0, 0, 0}, /* 0xF4 (11110100) */
+ {1, 3, 5, 6, 7, 8, 0, 0}, /* 0xF5 (11110101) */
+ {2, 3, 5, 6, 7, 8, 0, 0}, /* 0xF6 (11110110) */
+ {1, 2, 3, 5, 6, 7, 8, 0}, /* 0xF7 (11110111) */
+ {4, 5, 6, 7, 8, 0, 0, 0}, /* 0xF8 (11111000) */
+ {1, 4, 5, 6, 7, 8, 0, 0}, /* 0xF9 (11111001) */
+ {2, 4, 5, 6, 7, 8, 0, 0}, /* 0xFA (11111010) */
+ {1, 2, 4, 5, 6, 7, 8, 0}, /* 0xFB (11111011) */
+ {3, 4, 5, 6, 7, 8, 0, 0}, /* 0xFC (11111100) */
+ {1, 3, 4, 5, 6, 7, 8, 0}, /* 0xFD (11111101) */
+ {2, 3, 4, 5, 6, 7, 8, 0}, /* 0xFE (11111110) */
+ {1, 2, 3, 4, 5, 6, 7, 8} /* 0xFF (11111111) */
+};
+
+#endif // #ifdef USEAVX
+
+#ifdef IS_X64
+// same as vecDecodeTable but in 16 bits
+ALIGNED(32)
+static uint16_t vecDecodeTable_uint16[256][8] = {
+ {0, 0, 0, 0, 0, 0, 0, 0}, /* 0x00 (00000000) */
+ {1, 0, 0, 0, 0, 0, 0, 0}, /* 0x01 (00000001) */
+ {2, 0, 0, 0, 0, 0, 0, 0}, /* 0x02 (00000010) */
+ {1, 2, 0, 0, 0, 0, 0, 0}, /* 0x03 (00000011) */
+ {3, 0, 0, 0, 0, 0, 0, 0}, /* 0x04 (00000100) */
+ {1, 3, 0, 0, 0, 0, 0, 0}, /* 0x05 (00000101) */
+ {2, 3, 0, 0, 0, 0, 0, 0}, /* 0x06 (00000110) */
+ {1, 2, 3, 0, 0, 0, 0, 0}, /* 0x07 (00000111) */
+ {4, 0, 0, 0, 0, 0, 0, 0}, /* 0x08 (00001000) */
+ {1, 4, 0, 0, 0, 0, 0, 0}, /* 0x09 (00001001) */
+ {2, 4, 0, 0, 0, 0, 0, 0}, /* 0x0A (00001010) */
+ {1, 2, 4, 0, 0, 0, 0, 0}, /* 0x0B (00001011) */
+ {3, 4, 0, 0, 0, 0, 0, 0}, /* 0x0C (00001100) */
+ {1, 3, 4, 0, 0, 0, 0, 0}, /* 0x0D (00001101) */
+ {2, 3, 4, 0, 0, 0, 0, 0}, /* 0x0E (00001110) */
+ {1, 2, 3, 4, 0, 0, 0, 0}, /* 0x0F (00001111) */
+ {5, 0, 0, 0, 0, 0, 0, 0}, /* 0x10 (00010000) */
+ {1, 5, 0, 0, 0, 0, 0, 0}, /* 0x11 (00010001) */
+ {2, 5, 0, 0, 0, 0, 0, 0}, /* 0x12 (00010010) */
+ {1, 2, 5, 0, 0, 0, 0, 0}, /* 0x13 (00010011) */
+ {3, 5, 0, 0, 0, 0, 0, 0}, /* 0x14 (00010100) */
+ {1, 3, 5, 0, 0, 0, 0, 0}, /* 0x15 (00010101) */
+ {2, 3, 5, 0, 0, 0, 0, 0}, /* 0x16 (00010110) */
+ {1, 2, 3, 5, 0, 0, 0, 0}, /* 0x17 (00010111) */
+ {4, 5, 0, 0, 0, 0, 0, 0}, /* 0x18 (00011000) */
+ {1, 4, 5, 0, 0, 0, 0, 0}, /* 0x19 (00011001) */
+ {2, 4, 5, 0, 0, 0, 0, 0}, /* 0x1A (00011010) */
+ {1, 2, 4, 5, 0, 0, 0, 0}, /* 0x1B (00011011) */
+ {3, 4, 5, 0, 0, 0, 0, 0}, /* 0x1C (00011100) */
+ {1, 3, 4, 5, 0, 0, 0, 0}, /* 0x1D (00011101) */
+ {2, 3, 4, 5, 0, 0, 0, 0}, /* 0x1E (00011110) */
+ {1, 2, 3, 4, 5, 0, 0, 0}, /* 0x1F (00011111) */
+ {6, 0, 0, 0, 0, 0, 0, 0}, /* 0x20 (00100000) */
+ {1, 6, 0, 0, 0, 0, 0, 0}, /* 0x21 (00100001) */
+ {2, 6, 0, 0, 0, 0, 0, 0}, /* 0x22 (00100010) */
+ {1, 2, 6, 0, 0, 0, 0, 0}, /* 0x23 (00100011) */
+ {3, 6, 0, 0, 0, 0, 0, 0}, /* 0x24 (00100100) */
+ {1, 3, 6, 0, 0, 0, 0, 0}, /* 0x25 (00100101) */
+ {2, 3, 6, 0, 0, 0, 0, 0}, /* 0x26 (00100110) */
+ {1, 2, 3, 6, 0, 0, 0, 0}, /* 0x27 (00100111) */
+ {4, 6, 0, 0, 0, 0, 0, 0}, /* 0x28 (00101000) */
+ {1, 4, 6, 0, 0, 0, 0, 0}, /* 0x29 (00101001) */
+ {2, 4, 6, 0, 0, 0, 0, 0}, /* 0x2A (00101010) */
+ {1, 2, 4, 6, 0, 0, 0, 0}, /* 0x2B (00101011) */
+ {3, 4, 6, 0, 0, 0, 0, 0}, /* 0x2C (00101100) */
+ {1, 3, 4, 6, 0, 0, 0, 0}, /* 0x2D (00101101) */
+ {2, 3, 4, 6, 0, 0, 0, 0}, /* 0x2E (00101110) */
+ {1, 2, 3, 4, 6, 0, 0, 0}, /* 0x2F (00101111) */
+ {5, 6, 0, 0, 0, 0, 0, 0}, /* 0x30 (00110000) */
+ {1, 5, 6, 0, 0, 0, 0, 0}, /* 0x31 (00110001) */
+ {2, 5, 6, 0, 0, 0, 0, 0}, /* 0x32 (00110010) */
+ {1, 2, 5, 6, 0, 0, 0, 0}, /* 0x33 (00110011) */
+ {3, 5, 6, 0, 0, 0, 0, 0}, /* 0x34 (00110100) */
+ {1, 3, 5, 6, 0, 0, 0, 0}, /* 0x35 (00110101) */
+ {2, 3, 5, 6, 0, 0, 0, 0}, /* 0x36 (00110110) */
+ {1, 2, 3, 5, 6, 0, 0, 0}, /* 0x37 (00110111) */
+ {4, 5, 6, 0, 0, 0, 0, 0}, /* 0x38 (00111000) */
+ {1, 4, 5, 6, 0, 0, 0, 0}, /* 0x39 (00111001) */
+ {2, 4, 5, 6, 0, 0, 0, 0}, /* 0x3A (00111010) */
+ {1, 2, 4, 5, 6, 0, 0, 0}, /* 0x3B (00111011) */
+ {3, 4, 5, 6, 0, 0, 0, 0}, /* 0x3C (00111100) */
+ {1, 3, 4, 5, 6, 0, 0, 0}, /* 0x3D (00111101) */
+ {2, 3, 4, 5, 6, 0, 0, 0}, /* 0x3E (00111110) */
+ {1, 2, 3, 4, 5, 6, 0, 0}, /* 0x3F (00111111) */
+ {7, 0, 0, 0, 0, 0, 0, 0}, /* 0x40 (01000000) */
+ {1, 7, 0, 0, 0, 0, 0, 0}, /* 0x41 (01000001) */
+ {2, 7, 0, 0, 0, 0, 0, 0}, /* 0x42 (01000010) */
+ {1, 2, 7, 0, 0, 0, 0, 0}, /* 0x43 (01000011) */
+ {3, 7, 0, 0, 0, 0, 0, 0}, /* 0x44 (01000100) */
+ {1, 3, 7, 0, 0, 0, 0, 0}, /* 0x45 (01000101) */
+ {2, 3, 7, 0, 0, 0, 0, 0}, /* 0x46 (01000110) */
+ {1, 2, 3, 7, 0, 0, 0, 0}, /* 0x47 (01000111) */
+ {4, 7, 0, 0, 0, 0, 0, 0}, /* 0x48 (01001000) */
+ {1, 4, 7, 0, 0, 0, 0, 0}, /* 0x49 (01001001) */
+ {2, 4, 7, 0, 0, 0, 0, 0}, /* 0x4A (01001010) */
+ {1, 2, 4, 7, 0, 0, 0, 0}, /* 0x4B (01001011) */
+ {3, 4, 7, 0, 0, 0, 0, 0}, /* 0x4C (01001100) */
+ {1, 3, 4, 7, 0, 0, 0, 0}, /* 0x4D (01001101) */
+ {2, 3, 4, 7, 0, 0, 0, 0}, /* 0x4E (01001110) */
+ {1, 2, 3, 4, 7, 0, 0, 0}, /* 0x4F (01001111) */
+ {5, 7, 0, 0, 0, 0, 0, 0}, /* 0x50 (01010000) */
+ {1, 5, 7, 0, 0, 0, 0, 0}, /* 0x51 (01010001) */
+ {2, 5, 7, 0, 0, 0, 0, 0}, /* 0x52 (01010010) */
+ {1, 2, 5, 7, 0, 0, 0, 0}, /* 0x53 (01010011) */
+ {3, 5, 7, 0, 0, 0, 0, 0}, /* 0x54 (01010100) */
+ {1, 3, 5, 7, 0, 0, 0, 0}, /* 0x55 (01010101) */
+ {2, 3, 5, 7, 0, 0, 0, 0}, /* 0x56 (01010110) */
+ {1, 2, 3, 5, 7, 0, 0, 0}, /* 0x57 (01010111) */
+ {4, 5, 7, 0, 0, 0, 0, 0}, /* 0x58 (01011000) */
+ {1, 4, 5, 7, 0, 0, 0, 0}, /* 0x59 (01011001) */
+ {2, 4, 5, 7, 0, 0, 0, 0}, /* 0x5A (01011010) */
+ {1, 2, 4, 5, 7, 0, 0, 0}, /* 0x5B (01011011) */
+ {3, 4, 5, 7, 0, 0, 0, 0}, /* 0x5C (01011100) */
+ {1, 3, 4, 5, 7, 0, 0, 0}, /* 0x5D (01011101) */
+ {2, 3, 4, 5, 7, 0, 0, 0}, /* 0x5E (01011110) */
+ {1, 2, 3, 4, 5, 7, 0, 0}, /* 0x5F (01011111) */
+ {6, 7, 0, 0, 0, 0, 0, 0}, /* 0x60 (01100000) */
+ {1, 6, 7, 0, 0, 0, 0, 0}, /* 0x61 (01100001) */
+ {2, 6, 7, 0, 0, 0, 0, 0}, /* 0x62 (01100010) */
+ {1, 2, 6, 7, 0, 0, 0, 0}, /* 0x63 (01100011) */
+ {3, 6, 7, 0, 0, 0, 0, 0}, /* 0x64 (01100100) */
+ {1, 3, 6, 7, 0, 0, 0, 0}, /* 0x65 (01100101) */
+ {2, 3, 6, 7, 0, 0, 0, 0}, /* 0x66 (01100110) */
+ {1, 2, 3, 6, 7, 0, 0, 0}, /* 0x67 (01100111) */
+ {4, 6, 7, 0, 0, 0, 0, 0}, /* 0x68 (01101000) */
+ {1, 4, 6, 7, 0, 0, 0, 0}, /* 0x69 (01101001) */
+ {2, 4, 6, 7, 0, 0, 0, 0}, /* 0x6A (01101010) */
+ {1, 2, 4, 6, 7, 0, 0, 0}, /* 0x6B (01101011) */
+ {3, 4, 6, 7, 0, 0, 0, 0}, /* 0x6C (01101100) */
+ {1, 3, 4, 6, 7, 0, 0, 0}, /* 0x6D (01101101) */
+ {2, 3, 4, 6, 7, 0, 0, 0}, /* 0x6E (01101110) */
+ {1, 2, 3, 4, 6, 7, 0, 0}, /* 0x6F (01101111) */
+ {5, 6, 7, 0, 0, 0, 0, 0}, /* 0x70 (01110000) */
+ {1, 5, 6, 7, 0, 0, 0, 0}, /* 0x71 (01110001) */
+ {2, 5, 6, 7, 0, 0, 0, 0}, /* 0x72 (01110010) */
+ {1, 2, 5, 6, 7, 0, 0, 0}, /* 0x73 (01110011) */
+ {3, 5, 6, 7, 0, 0, 0, 0}, /* 0x74 (01110100) */
+ {1, 3, 5, 6, 7, 0, 0, 0}, /* 0x75 (01110101) */
+ {2, 3, 5, 6, 7, 0, 0, 0}, /* 0x76 (01110110) */
+ {1, 2, 3, 5, 6, 7, 0, 0}, /* 0x77 (01110111) */
+ {4, 5, 6, 7, 0, 0, 0, 0}, /* 0x78 (01111000) */
+ {1, 4, 5, 6, 7, 0, 0, 0}, /* 0x79 (01111001) */
+ {2, 4, 5, 6, 7, 0, 0, 0}, /* 0x7A (01111010) */
+ {1, 2, 4, 5, 6, 7, 0, 0}, /* 0x7B (01111011) */
+ {3, 4, 5, 6, 7, 0, 0, 0}, /* 0x7C (01111100) */
+ {1, 3, 4, 5, 6, 7, 0, 0}, /* 0x7D (01111101) */
+ {2, 3, 4, 5, 6, 7, 0, 0}, /* 0x7E (01111110) */
+ {1, 2, 3, 4, 5, 6, 7, 0}, /* 0x7F (01111111) */
+ {8, 0, 0, 0, 0, 0, 0, 0}, /* 0x80 (10000000) */
+ {1, 8, 0, 0, 0, 0, 0, 0}, /* 0x81 (10000001) */
+ {2, 8, 0, 0, 0, 0, 0, 0}, /* 0x82 (10000010) */
+ {1, 2, 8, 0, 0, 0, 0, 0}, /* 0x83 (10000011) */
+ {3, 8, 0, 0, 0, 0, 0, 0}, /* 0x84 (10000100) */
+ {1, 3, 8, 0, 0, 0, 0, 0}, /* 0x85 (10000101) */
+ {2, 3, 8, 0, 0, 0, 0, 0}, /* 0x86 (10000110) */
+ {1, 2, 3, 8, 0, 0, 0, 0}, /* 0x87 (10000111) */
+ {4, 8, 0, 0, 0, 0, 0, 0}, /* 0x88 (10001000) */
+ {1, 4, 8, 0, 0, 0, 0, 0}, /* 0x89 (10001001) */
+ {2, 4, 8, 0, 0, 0, 0, 0}, /* 0x8A (10001010) */
+ {1, 2, 4, 8, 0, 0, 0, 0}, /* 0x8B (10001011) */
+ {3, 4, 8, 0, 0, 0, 0, 0}, /* 0x8C (10001100) */
+ {1, 3, 4, 8, 0, 0, 0, 0}, /* 0x8D (10001101) */
+ {2, 3, 4, 8, 0, 0, 0, 0}, /* 0x8E (10001110) */
+ {1, 2, 3, 4, 8, 0, 0, 0}, /* 0x8F (10001111) */
+ {5, 8, 0, 0, 0, 0, 0, 0}, /* 0x90 (10010000) */
+ {1, 5, 8, 0, 0, 0, 0, 0}, /* 0x91 (10010001) */
+ {2, 5, 8, 0, 0, 0, 0, 0}, /* 0x92 (10010010) */
+ {1, 2, 5, 8, 0, 0, 0, 0}, /* 0x93 (10010011) */
+ {3, 5, 8, 0, 0, 0, 0, 0}, /* 0x94 (10010100) */
+ {1, 3, 5, 8, 0, 0, 0, 0}, /* 0x95 (10010101) */
+ {2, 3, 5, 8, 0, 0, 0, 0}, /* 0x96 (10010110) */
+ {1, 2, 3, 5, 8, 0, 0, 0}, /* 0x97 (10010111) */
+ {4, 5, 8, 0, 0, 0, 0, 0}, /* 0x98 (10011000) */
+ {1, 4, 5, 8, 0, 0, 0, 0}, /* 0x99 (10011001) */
+ {2, 4, 5, 8, 0, 0, 0, 0}, /* 0x9A (10011010) */
+ {1, 2, 4, 5, 8, 0, 0, 0}, /* 0x9B (10011011) */
+ {3, 4, 5, 8, 0, 0, 0, 0}, /* 0x9C (10011100) */
+ {1, 3, 4, 5, 8, 0, 0, 0}, /* 0x9D (10011101) */
+ {2, 3, 4, 5, 8, 0, 0, 0}, /* 0x9E (10011110) */
+ {1, 2, 3, 4, 5, 8, 0, 0}, /* 0x9F (10011111) */
+ {6, 8, 0, 0, 0, 0, 0, 0}, /* 0xA0 (10100000) */
+ {1, 6, 8, 0, 0, 0, 0, 0}, /* 0xA1 (10100001) */
+ {2, 6, 8, 0, 0, 0, 0, 0}, /* 0xA2 (10100010) */
+ {1, 2, 6, 8, 0, 0, 0, 0}, /* 0xA3 (10100011) */
+ {3, 6, 8, 0, 0, 0, 0, 0}, /* 0xA4 (10100100) */
+ {1, 3, 6, 8, 0, 0, 0, 0}, /* 0xA5 (10100101) */
+ {2, 3, 6, 8, 0, 0, 0, 0}, /* 0xA6 (10100110) */
+ {1, 2, 3, 6, 8, 0, 0, 0}, /* 0xA7 (10100111) */
+ {4, 6, 8, 0, 0, 0, 0, 0}, /* 0xA8 (10101000) */
+ {1, 4, 6, 8, 0, 0, 0, 0}, /* 0xA9 (10101001) */
+ {2, 4, 6, 8, 0, 0, 0, 0}, /* 0xAA (10101010) */
+ {1, 2, 4, 6, 8, 0, 0, 0}, /* 0xAB (10101011) */
+ {3, 4, 6, 8, 0, 0, 0, 0}, /* 0xAC (10101100) */
+ {1, 3, 4, 6, 8, 0, 0, 0}, /* 0xAD (10101101) */
+ {2, 3, 4, 6, 8, 0, 0, 0}, /* 0xAE (10101110) */
+ {1, 2, 3, 4, 6, 8, 0, 0}, /* 0xAF (10101111) */
+ {5, 6, 8, 0, 0, 0, 0, 0}, /* 0xB0 (10110000) */
+ {1, 5, 6, 8, 0, 0, 0, 0}, /* 0xB1 (10110001) */
+ {2, 5, 6, 8, 0, 0, 0, 0}, /* 0xB2 (10110010) */
+ {1, 2, 5, 6, 8, 0, 0, 0}, /* 0xB3 (10110011) */
+ {3, 5, 6, 8, 0, 0, 0, 0}, /* 0xB4 (10110100) */
+ {1, 3, 5, 6, 8, 0, 0, 0}, /* 0xB5 (10110101) */
+ {2, 3, 5, 6, 8, 0, 0, 0}, /* 0xB6 (10110110) */
+ {1, 2, 3, 5, 6, 8, 0, 0}, /* 0xB7 (10110111) */
+ {4, 5, 6, 8, 0, 0, 0, 0}, /* 0xB8 (10111000) */
+ {1, 4, 5, 6, 8, 0, 0, 0}, /* 0xB9 (10111001) */
+ {2, 4, 5, 6, 8, 0, 0, 0}, /* 0xBA (10111010) */
+ {1, 2, 4, 5, 6, 8, 0, 0}, /* 0xBB (10111011) */
+ {3, 4, 5, 6, 8, 0, 0, 0}, /* 0xBC (10111100) */
+ {1, 3, 4, 5, 6, 8, 0, 0}, /* 0xBD (10111101) */
+ {2, 3, 4, 5, 6, 8, 0, 0}, /* 0xBE (10111110) */
+ {1, 2, 3, 4, 5, 6, 8, 0}, /* 0xBF (10111111) */
+ {7, 8, 0, 0, 0, 0, 0, 0}, /* 0xC0 (11000000) */
+ {1, 7, 8, 0, 0, 0, 0, 0}, /* 0xC1 (11000001) */
+ {2, 7, 8, 0, 0, 0, 0, 0}, /* 0xC2 (11000010) */
+ {1, 2, 7, 8, 0, 0, 0, 0}, /* 0xC3 (11000011) */
+ {3, 7, 8, 0, 0, 0, 0, 0}, /* 0xC4 (11000100) */
+ {1, 3, 7, 8, 0, 0, 0, 0}, /* 0xC5 (11000101) */
+ {2, 3, 7, 8, 0, 0, 0, 0}, /* 0xC6 (11000110) */
+ {1, 2, 3, 7, 8, 0, 0, 0}, /* 0xC7 (11000111) */
+ {4, 7, 8, 0, 0, 0, 0, 0}, /* 0xC8 (11001000) */
+ {1, 4, 7, 8, 0, 0, 0, 0}, /* 0xC9 (11001001) */
+ {2, 4, 7, 8, 0, 0, 0, 0}, /* 0xCA (11001010) */
+ {1, 2, 4, 7, 8, 0, 0, 0}, /* 0xCB (11001011) */
+ {3, 4, 7, 8, 0, 0, 0, 0}, /* 0xCC (11001100) */
+ {1, 3, 4, 7, 8, 0, 0, 0}, /* 0xCD (11001101) */
+ {2, 3, 4, 7, 8, 0, 0, 0}, /* 0xCE (11001110) */
+ {1, 2, 3, 4, 7, 8, 0, 0}, /* 0xCF (11001111) */
+ {5, 7, 8, 0, 0, 0, 0, 0}, /* 0xD0 (11010000) */
+ {1, 5, 7, 8, 0, 0, 0, 0}, /* 0xD1 (11010001) */
+ {2, 5, 7, 8, 0, 0, 0, 0}, /* 0xD2 (11010010) */
+ {1, 2, 5, 7, 8, 0, 0, 0}, /* 0xD3 (11010011) */
+ {3, 5, 7, 8, 0, 0, 0, 0}, /* 0xD4 (11010100) */
+ {1, 3, 5, 7, 8, 0, 0, 0}, /* 0xD5 (11010101) */
+ {2, 3, 5, 7, 8, 0, 0, 0}, /* 0xD6 (11010110) */
+ {1, 2, 3, 5, 7, 8, 0, 0}, /* 0xD7 (11010111) */
+ {4, 5, 7, 8, 0, 0, 0, 0}, /* 0xD8 (11011000) */
+ {1, 4, 5, 7, 8, 0, 0, 0}, /* 0xD9 (11011001) */
+ {2, 4, 5, 7, 8, 0, 0, 0}, /* 0xDA (11011010) */
+ {1, 2, 4, 5, 7, 8, 0, 0}, /* 0xDB (11011011) */
+ {3, 4, 5, 7, 8, 0, 0, 0}, /* 0xDC (11011100) */
+ {1, 3, 4, 5, 7, 8, 0, 0}, /* 0xDD (11011101) */
+ {2, 3, 4, 5, 7, 8, 0, 0}, /* 0xDE (11011110) */
+ {1, 2, 3, 4, 5, 7, 8, 0}, /* 0xDF (11011111) */
+ {6, 7, 8, 0, 0, 0, 0, 0}, /* 0xE0 (11100000) */
+ {1, 6, 7, 8, 0, 0, 0, 0}, /* 0xE1 (11100001) */
+ {2, 6, 7, 8, 0, 0, 0, 0}, /* 0xE2 (11100010) */
+ {1, 2, 6, 7, 8, 0, 0, 0}, /* 0xE3 (11100011) */
+ {3, 6, 7, 8, 0, 0, 0, 0}, /* 0xE4 (11100100) */
+ {1, 3, 6, 7, 8, 0, 0, 0}, /* 0xE5 (11100101) */
+ {2, 3, 6, 7, 8, 0, 0, 0}, /* 0xE6 (11100110) */
+ {1, 2, 3, 6, 7, 8, 0, 0}, /* 0xE7 (11100111) */
+ {4, 6, 7, 8, 0, 0, 0, 0}, /* 0xE8 (11101000) */
+ {1, 4, 6, 7, 8, 0, 0, 0}, /* 0xE9 (11101001) */
+ {2, 4, 6, 7, 8, 0, 0, 0}, /* 0xEA (11101010) */
+ {1, 2, 4, 6, 7, 8, 0, 0}, /* 0xEB (11101011) */
+ {3, 4, 6, 7, 8, 0, 0, 0}, /* 0xEC (11101100) */
+ {1, 3, 4, 6, 7, 8, 0, 0}, /* 0xED (11101101) */
+ {2, 3, 4, 6, 7, 8, 0, 0}, /* 0xEE (11101110) */
+ {1, 2, 3, 4, 6, 7, 8, 0}, /* 0xEF (11101111) */
+ {5, 6, 7, 8, 0, 0, 0, 0}, /* 0xF0 (11110000) */
+ {1, 5, 6, 7, 8, 0, 0, 0}, /* 0xF1 (11110001) */
+ {2, 5, 6, 7, 8, 0, 0, 0}, /* 0xF2 (11110010) */
+ {1, 2, 5, 6, 7, 8, 0, 0}, /* 0xF3 (11110011) */
+ {3, 5, 6, 7, 8, 0, 0, 0}, /* 0xF4 (11110100) */
+ {1, 3, 5, 6, 7, 8, 0, 0}, /* 0xF5 (11110101) */
+ {2, 3, 5, 6, 7, 8, 0, 0}, /* 0xF6 (11110110) */
+ {1, 2, 3, 5, 6, 7, 8, 0}, /* 0xF7 (11110111) */
+ {4, 5, 6, 7, 8, 0, 0, 0}, /* 0xF8 (11111000) */
+ {1, 4, 5, 6, 7, 8, 0, 0}, /* 0xF9 (11111001) */
+ {2, 4, 5, 6, 7, 8, 0, 0}, /* 0xFA (11111010) */
+ {1, 2, 4, 5, 6, 7, 8, 0}, /* 0xFB (11111011) */
+ {3, 4, 5, 6, 7, 8, 0, 0}, /* 0xFC (11111100) */
+ {1, 3, 4, 5, 6, 7, 8, 0}, /* 0xFD (11111101) */
+ {2, 3, 4, 5, 6, 7, 8, 0}, /* 0xFE (11111110) */
+ {1, 2, 3, 4, 5, 6, 7, 8} /* 0xFF (11111111) */
+};
+
+#endif
+
+#ifdef USEAVX
+
+size_t bitset_extract_setbits_avx2(uint64_t *array, size_t length, void *vout,
+ size_t outcapacity, uint32_t base) {
+ uint32_t *out = (uint32_t *)vout;
+ uint32_t *initout = out;
+ __m256i baseVec = _mm256_set1_epi32(base - 1);
+ __m256i incVec = _mm256_set1_epi32(64);
+ __m256i add8 = _mm256_set1_epi32(8);
+ uint32_t *safeout = out + outcapacity;
+ size_t i = 0;
+ for (; (i < length) && (out + 64 <= safeout); ++i) {
+ uint64_t w = array[i];
+ if (w == 0) {
+ baseVec = _mm256_add_epi32(baseVec, incVec);
+ } else {
+ for (int k = 0; k < 4; ++k) {
+ uint8_t byteA = (uint8_t)w;
+ uint8_t byteB = (uint8_t)(w >> 8);
+ w >>= 16;
+ __m256i vecA =
+ _mm256_load_si256((const __m256i *)vecDecodeTable[byteA]);
+ __m256i vecB =
+ _mm256_load_si256((const __m256i *)vecDecodeTable[byteB]);
+ uint8_t advanceA = lengthTable[byteA];
+ uint8_t advanceB = lengthTable[byteB];
+ vecA = _mm256_add_epi32(baseVec, vecA);
+ baseVec = _mm256_add_epi32(baseVec, add8);
+ vecB = _mm256_add_epi32(baseVec, vecB);
+ baseVec = _mm256_add_epi32(baseVec, add8);
+ _mm256_storeu_si256((__m256i *)out, vecA);
+ out += advanceA;
+ _mm256_storeu_si256((__m256i *)out, vecB);
+ out += advanceB;
+ }
+ }
+ }
+ base += i * 64;
+ for (; (i < length) && (out < safeout); ++i) {
+ uint64_t w = array[i];
+ while ((w != 0) && (out < safeout)) {
+ uint64_t t = w & (~w + 1); // on x64, should compile to BLSI (careful: the Intel compiler seems to fail)
+ int r = __builtin_ctzll(w); // on x64, should compile to TZCNT
+ uint32_t val = r + base;
+ memcpy(out, &val,
+ sizeof(uint32_t)); // should be compiled as a MOV on x64
+ out++;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return out - initout;
+}
+#endif // USEAVX
+
+size_t bitset_extract_setbits(uint64_t *bitset, size_t length, void *vout,
+ uint32_t base) {
+ int outpos = 0;
+ uint32_t *out = (uint32_t *)vout;
+ for (size_t i = 0; i < length; ++i) {
+ uint64_t w = bitset[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1); // on x64, should compile to BLSI (careful: the Intel compiler seems to fail)
+ int r = __builtin_ctzll(w); // on x64, should compile to TZCNT
+ uint32_t val = r + base;
+ memcpy(out + outpos, &val,
+ sizeof(uint32_t)); // should be compiled as a MOV on x64
+ outpos++;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return outpos;
+}
+
+size_t bitset_extract_intersection_setbits_uint16(const uint64_t * __restrict__ bitset1,
+ const uint64_t * __restrict__ bitset2,
+ size_t length, uint16_t *out,
+ uint16_t base) {
+ int outpos = 0;
+ for (size_t i = 0; i < length; ++i) {
+ uint64_t w = bitset1[i] & bitset2[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ out[outpos++] = r + base;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return outpos;
+}
+
+#ifdef IS_X64
+/*
+ * Given a bitset containing "length" 64-bit words, write out the position
+ * of all the set bits to "out" as 16-bit integers, values start at "base" (can
+ *be set to zero).
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ *set.
+ *
+ * Returns how many values were actually decoded.
+ *
+ * This function uses SSE decoding.
+ */
+size_t bitset_extract_setbits_sse_uint16(const uint64_t *bitset, size_t length,
+ uint16_t *out, size_t outcapacity,
+ uint16_t base) {
+ uint16_t *initout = out;
+ __m128i baseVec = _mm_set1_epi16(base - 1);
+ __m128i incVec = _mm_set1_epi16(64);
+ __m128i add8 = _mm_set1_epi16(8);
+ uint16_t *safeout = out + outcapacity;
+ const int numberofbytes = 2; // process two bytes at a time
+ size_t i = 0;
+ for (; (i < length) && (out + numberofbytes * 8 <= safeout); ++i) {
+ uint64_t w = bitset[i];
+ if (w == 0) {
+ baseVec = _mm_add_epi16(baseVec, incVec);
+ } else {
+ for (int k = 0; k < 4; ++k) {
+ uint8_t byteA = (uint8_t)w;
+ uint8_t byteB = (uint8_t)(w >> 8);
+ w >>= 16;
+ __m128i vecA = _mm_load_si128(
+ (const __m128i *)vecDecodeTable_uint16[byteA]);
+ __m128i vecB = _mm_load_si128(
+ (const __m128i *)vecDecodeTable_uint16[byteB]);
+ uint8_t advanceA = lengthTable[byteA];
+ uint8_t advanceB = lengthTable[byteB];
+ vecA = _mm_add_epi16(baseVec, vecA);
+ baseVec = _mm_add_epi16(baseVec, add8);
+ vecB = _mm_add_epi16(baseVec, vecB);
+ baseVec = _mm_add_epi16(baseVec, add8);
+ _mm_storeu_si128((__m128i *)out, vecA);
+ out += advanceA;
+ _mm_storeu_si128((__m128i *)out, vecB);
+ out += advanceB;
+ }
+ }
+ }
+ base += (uint16_t)(i * 64);
+ for (; (i < length) && (out < safeout); ++i) {
+ uint64_t w = bitset[i];
+ while ((w != 0) && (out < safeout)) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ *out = r + base;
+ out++;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return out - initout;
+}
+#endif
+
+/*
+ * Given a bitset containing "length" 64-bit words, write out the position
+ * of all the set bits to "out", values start at "base" (can be set to zero).
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ *set.
+ *
+ * Returns how many values were actually decoded.
+ */
+size_t bitset_extract_setbits_uint16(const uint64_t *bitset, size_t length,
+ uint16_t *out, uint16_t base) {
+ int outpos = 0;
+ for (size_t i = 0; i < length; ++i) {
+ uint64_t w = bitset[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ out[outpos++] = r + base;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return outpos;
+}
+
+#if defined(ASMBITMANIPOPTIMIZATION)
+
+uint64_t bitset_set_list_withcard(void *bitset, uint64_t card,
+ const uint16_t *list, uint64_t length) {
+ uint64_t offset, load, pos;
+ uint64_t shift = 6;
+ const uint16_t *end = list + length;
+ if (!length) return card;
+ // TODO: could unroll for performance, see bitset_set_list
+ // bts is not available as an intrinsic in GCC
+ __asm volatile(
+ "1:\n"
+ "movzwq (%[list]), %[pos]\n"
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "bts %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)\n"
+ "sbb $-1, %[card]\n"
+ "add $2, %[list]\n"
+ "cmp %[list], %[end]\n"
+ "jnz 1b"
+ : [card] "+&r"(card), [list] "+&r"(list), [load] "=&r"(load),
+ [pos] "=&r"(pos), [offset] "=&r"(offset)
+ : [end] "r"(end), [bitset] "r"(bitset), [shift] "r"(shift));
+ return card;
+}
+
+void bitset_set_list(void *bitset, const uint16_t *list, uint64_t length) {
+ uint64_t pos;
+ const uint16_t *end = list + length;
+
+ uint64_t shift = 6;
+ uint64_t offset;
+ uint64_t load;
+ for (; list + 3 < end; list += 4) {
+ pos = list[0];
+ __asm volatile(
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "bts %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)"
+ : [load] "=&r"(load), [offset] "=&r"(offset)
+ : [bitset] "r"(bitset), [shift] "r"(shift), [pos] "r"(pos));
+ pos = list[1];
+ __asm volatile(
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "bts %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)"
+ : [load] "=&r"(load), [offset] "=&r"(offset)
+ : [bitset] "r"(bitset), [shift] "r"(shift), [pos] "r"(pos));
+ pos = list[2];
+ __asm volatile(
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "bts %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)"
+ : [load] "=&r"(load), [offset] "=&r"(offset)
+ : [bitset] "r"(bitset), [shift] "r"(shift), [pos] "r"(pos));
+ pos = list[3];
+ __asm volatile(
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "bts %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)"
+ : [load] "=&r"(load), [offset] "=&r"(offset)
+ : [bitset] "r"(bitset), [shift] "r"(shift), [pos] "r"(pos));
+ }
+
+ while (list != end) {
+ pos = list[0];
+ __asm volatile(
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "bts %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)"
+ : [load] "=&r"(load), [offset] "=&r"(offset)
+ : [bitset] "r"(bitset), [shift] "r"(shift), [pos] "r"(pos));
+ list++;
+ }
+}
+
+uint64_t bitset_clear_list(void *bitset, uint64_t card, const uint16_t *list,
+ uint64_t length) {
+ uint64_t offset, load, pos;
+ uint64_t shift = 6;
+ const uint16_t *end = list + length;
+ if (!length) return card;
+ // btr is not available as an intrinsic in GCC
+ __asm volatile(
+ "1:\n"
+ "movzwq (%[list]), %[pos]\n"
+ "shrx %[shift], %[pos], %[offset]\n"
+ "mov (%[bitset],%[offset],8), %[load]\n"
+ "btr %[pos], %[load]\n"
+ "mov %[load], (%[bitset],%[offset],8)\n"
+ "sbb $0, %[card]\n"
+ "add $2, %[list]\n"
+ "cmp %[list], %[end]\n"
+ "jnz 1b"
+ : [card] "+&r"(card), [list] "+&r"(list), [load] "=&r"(load),
+ [pos] "=&r"(pos), [offset] "=&r"(offset)
+ : [end] "r"(end), [bitset] "r"(bitset), [shift] "r"(shift)
+ :
+ /* clobbers */ "memory");
+ return card;
+}
+
+#else
+uint64_t bitset_clear_list(void *bitset, uint64_t card, const uint16_t *list,
+ uint64_t length) {
+ uint64_t offset, load, newload, pos, index;
+ const uint16_t *end = list + length;
+ while (list != end) {
+ pos = *(const uint16_t *)list;
+ offset = pos >> 6;
+ index = pos % 64;
+ load = ((uint64_t *)bitset)[offset];
+ newload = load & ~(UINT64_C(1) << index);
+ card -= (load ^ newload) >> index;
+ ((uint64_t *)bitset)[offset] = newload;
+ list++;
+ }
+ return card;
+}
+
+uint64_t bitset_set_list_withcard(void *bitset, uint64_t card,
+ const uint16_t *list, uint64_t length) {
+ uint64_t offset, load, newload, pos, index;
+ const uint16_t *end = list + length;
+ while (list != end) {
+ pos = *(const uint16_t *)list;
+ offset = pos >> 6;
+ index = pos % 64;
+ load = ((uint64_t *)bitset)[offset];
+ newload = load | (UINT64_C(1) << index);
+ card += (load ^ newload) >> index;
+ ((uint64_t *)bitset)[offset] = newload;
+ list++;
+ }
+ return card;
+}
+
+void bitset_set_list(void *bitset, const uint16_t *list, uint64_t length) {
+ uint64_t offset, load, newload, pos, index;
+ const uint16_t *end = list + length;
+ while (list != end) {
+ pos = *(const uint16_t *)list;
+ offset = pos >> 6;
+ index = pos % 64;
+ load = ((uint64_t *)bitset)[offset];
+ newload = load | (UINT64_C(1) << index);
+ ((uint64_t *)bitset)[offset] = newload;
+ list++;
+ }
+}
+
+#endif
+
+/* flip specified bits */
+/* TODO: consider whether worthwhile to make an asm version */
+
+uint64_t bitset_flip_list_withcard(void *bitset, uint64_t card,
+ const uint16_t *list, uint64_t length) {
+ uint64_t offset, load, newload, pos, index;
+ const uint16_t *end = list + length;
+ while (list != end) {
+ pos = *(const uint16_t *)list;
+ offset = pos >> 6;
+ index = pos % 64;
+ load = ((uint64_t *)bitset)[offset];
+ newload = load ^ (UINT64_C(1) << index);
+ // todo: is a branch here all that bad?
+ card +=
+ (1 - 2 * (((UINT64_C(1) << index) & load) >> index)); // +1 or -1
+ ((uint64_t *)bitset)[offset] = newload;
+ list++;
+ }
+ return card;
+}
+
+void bitset_flip_list(void *bitset, const uint16_t *list, uint64_t length) {
+ uint64_t offset, load, newload, pos, index;
+ const uint16_t *end = list + length;
+ while (list != end) {
+ pos = *(const uint16_t *)list;
+ offset = pos >> 6;
+ index = pos % 64;
+ load = ((uint64_t *)bitset)[offset];
+ newload = load ^ (UINT64_C(1) << index);
+ ((uint64_t *)bitset)[offset] = newload;
+ list++;
+ }
+}
+/* end file src/bitset_util.c */
+/* begin file src/containers/array.c */
+/*
+ * array.c
+ *
+ */
+
+#include
+#include
+#include
+
+/* Create a new array with capacity size. Return NULL in case of failure. */
+array_container_t *array_container_create_given_capacity(int32_t size) {
+ array_container_t *container;
+
+ container = (array_container_t *)malloc(sizeof(array_container_t));
+ assert (container);
+
+ if( size <= 0 ) { // we don't want to rely on malloc(0)
+ container->array = NULL;
+ } else {
+ container->array = (uint16_t *)malloc(sizeof(uint16_t) * size);
+ assert (container->array);
+ }
+
+ container->capacity = size;
+ container->cardinality = 0;
+
+ return container;
+}
+
+/* Create a new array. Return NULL in case of failure. */
+array_container_t *array_container_create(void) {
+ return array_container_create_given_capacity(ARRAY_DEFAULT_INIT_SIZE);
+}
+
+/* Create a new array containing all values in [min,max). */
+array_container_t * array_container_create_range(uint32_t min, uint32_t max) {
+ array_container_t * answer = array_container_create_given_capacity(max - min + 1);
+ if(answer == NULL) return answer;
+ answer->cardinality = 0;
+ for(uint32_t k = min; k < max; k++) {
+ answer->array[answer->cardinality++] = k;
+ }
+ return answer;
+}
+
+/* Duplicate container */
+array_container_t *array_container_clone(const array_container_t *src) {
+ array_container_t *newcontainer =
+ array_container_create_given_capacity(src->capacity);
+ if (newcontainer == NULL) return NULL;
+
+ newcontainer->cardinality = src->cardinality;
+
+ memcpy(newcontainer->array, src->array,
+ src->cardinality * sizeof(uint16_t));
+
+ return newcontainer;
+}
+
+int array_container_shrink_to_fit(array_container_t *src) {
+ if (src->cardinality == src->capacity) return 0; // nothing to do
+ int savings = src->capacity - src->cardinality;
+ src->capacity = src->cardinality;
+ if( src->capacity == 0) { // we do not want to rely on realloc for zero allocs
+ free(src->array);
+ src->array = NULL;
+ } else {
+ uint16_t *oldarray = src->array;
+ src->array =
+ (uint16_t *)realloc(oldarray, src->capacity * sizeof(uint16_t));
+ }
+ return savings;
+}
+
+/* Free memory. */
+void array_container_free(array_container_t *arr) {
+ if(arr->array != NULL) {// Jon Strabala reports that some tools complain otherwise
+ free(arr->array);
+ arr->array = NULL; // pedantic
+ }
+ free(arr);
+}
+
+static inline int32_t grow_capacity(int32_t capacity) {
+ return (capacity <= 0) ? ARRAY_DEFAULT_INIT_SIZE
+ : capacity < 64 ? capacity * 2
+ : capacity < 1024 ? capacity * 3 / 2
+ : capacity * 5 / 4;
+}
+
+static inline int32_t clamp(int32_t val, int32_t min, int32_t max) {
+ return ((val < min) ? min : (val > max) ? max : val);
+}
+
+void array_container_grow(array_container_t *container, int32_t min,
+ bool preserve) {
+
+ int32_t max = (min <= DEFAULT_MAX_SIZE ? DEFAULT_MAX_SIZE : 65536);
+ int32_t new_capacity = clamp(grow_capacity(container->capacity), min, max);
+
+ container->capacity = new_capacity;
+ uint16_t *array = container->array;
+
+ if (preserve) {
+ container->array =
+ (uint16_t *)realloc(array, new_capacity * sizeof(uint16_t));
+ } else {
+ // Jon Strabala reports that some tools complain otherwise
+ if (array != NULL) {
+ free(array);
+ }
+ container->array = (uint16_t *)malloc(new_capacity * sizeof(uint16_t));
+ }
+
+ // handle the case where realloc fails
+ if (container->array == NULL) {
+ fprintf(stderr, "could not allocate memory\n");
+ }
+ assert(container->array != NULL);
+}
+
+/* Copy one container into another. We assume that they are distinct. */
+void array_container_copy(const array_container_t *src,
+ array_container_t *dst) {
+ const int32_t cardinality = src->cardinality;
+ if (cardinality > dst->capacity) {
+ array_container_grow(dst, cardinality, false);
+ }
+
+ dst->cardinality = cardinality;
+ memcpy(dst->array, src->array, cardinality * sizeof(uint16_t));
+}
+
+void array_container_add_from_range(array_container_t *arr, uint32_t min,
+ uint32_t max, uint16_t step) {
+ for (uint32_t value = min; value < max; value += step) {
+ array_container_append(arr, value);
+ }
+}
+
+/* Computes the union of array1 and array2 and write the result to arrayout.
+ * It is assumed that arrayout is distinct from both array1 and array2.
+ */
+void array_container_union(const array_container_t *array_1,
+ const array_container_t *array_2,
+ array_container_t *out) {
+ const int32_t card_1 = array_1->cardinality, card_2 = array_2->cardinality;
+ const int32_t max_cardinality = card_1 + card_2;
+
+ if (out->capacity < max_cardinality) {
+ array_container_grow(out, max_cardinality, false);
+ }
+ out->cardinality = (int32_t)fast_union_uint16(array_1->array, card_1,
+ array_2->array, card_2, out->array);
+
+}
+
+/* Computes the difference of array1 and array2 and write the result
+ * to array out.
+ * Array out does not need to be distinct from array_1
+ */
+void array_container_andnot(const array_container_t *array_1,
+ const array_container_t *array_2,
+ array_container_t *out) {
+ if (out->capacity < array_1->cardinality)
+ array_container_grow(out, array_1->cardinality, false);
+#ifdef ROARING_VECTOR_OPERATIONS_ENABLED
+ if((out != array_1) && (out != array_2)) {
+ out->cardinality =
+ difference_vector16(array_1->array, array_1->cardinality,
+ array_2->array, array_2->cardinality, out->array);
+ } else {
+ out->cardinality =
+ difference_uint16(array_1->array, array_1->cardinality, array_2->array,
+ array_2->cardinality, out->array);
+ }
+#else
+ out->cardinality =
+ difference_uint16(array_1->array, array_1->cardinality, array_2->array,
+ array_2->cardinality, out->array);
+#endif
+}
+
+/* Computes the symmetric difference of array1 and array2 and write the
+ * result
+ * to arrayout.
+ * It is assumed that arrayout is distinct from both array1 and array2.
+ */
+void array_container_xor(const array_container_t *array_1,
+ const array_container_t *array_2,
+ array_container_t *out) {
+ const int32_t card_1 = array_1->cardinality, card_2 = array_2->cardinality;
+ const int32_t max_cardinality = card_1 + card_2;
+ if (out->capacity < max_cardinality) {
+ array_container_grow(out, max_cardinality, false);
+ }
+
+#ifdef ROARING_VECTOR_OPERATIONS_ENABLED
+ out->cardinality =
+ xor_vector16(array_1->array, array_1->cardinality, array_2->array,
+ array_2->cardinality, out->array);
+#else
+ out->cardinality =
+ xor_uint16(array_1->array, array_1->cardinality, array_2->array,
+ array_2->cardinality, out->array);
+#endif
+}
+
+static inline int32_t minimum_int32(int32_t a, int32_t b) {
+ return (a < b) ? a : b;
+}
+
+/* computes the intersection of array1 and array2 and write the result to
+ * arrayout.
+ * It is assumed that arrayout is distinct from both array1 and array2.
+ * */
+void array_container_intersection(const array_container_t *array1,
+ const array_container_t *array2,
+ array_container_t *out) {
+ int32_t card_1 = array1->cardinality, card_2 = array2->cardinality,
+ min_card = minimum_int32(card_1, card_2);
+ const int threshold = 64; // subject to tuning
+#ifdef USEAVX
+ if (out->capacity < min_card) {
+ array_container_grow(out, min_card + sizeof(__m128i) / sizeof(uint16_t),
+ false);
+ }
+#else
+ if (out->capacity < min_card) {
+ array_container_grow(out, min_card, false);
+ }
+#endif
+
+ if (card_1 * threshold < card_2) {
+ out->cardinality = intersect_skewed_uint16(
+ array1->array, card_1, array2->array, card_2, out->array);
+ } else if (card_2 * threshold < card_1) {
+ out->cardinality = intersect_skewed_uint16(
+ array2->array, card_2, array1->array, card_1, out->array);
+ } else {
+#ifdef USEAVX
+ out->cardinality = intersect_vector16(
+ array1->array, card_1, array2->array, card_2, out->array);
+#else
+ out->cardinality = intersect_uint16(array1->array, card_1,
+ array2->array, card_2, out->array);
+#endif
+ }
+}
+
+/* computes the size of the intersection of array1 and array2
+ * */
+int array_container_intersection_cardinality(const array_container_t *array1,
+ const array_container_t *array2) {
+ int32_t card_1 = array1->cardinality, card_2 = array2->cardinality;
+ const int threshold = 64; // subject to tuning
+ if (card_1 * threshold < card_2) {
+ return intersect_skewed_uint16_cardinality(array1->array, card_1,
+ array2->array, card_2);
+ } else if (card_2 * threshold < card_1) {
+ return intersect_skewed_uint16_cardinality(array2->array, card_2,
+ array1->array, card_1);
+ } else {
+#ifdef USEAVX
+ return intersect_vector16_cardinality(array1->array, card_1,
+ array2->array, card_2);
+#else
+ return intersect_uint16_cardinality(array1->array, card_1,
+ array2->array, card_2);
+#endif
+ }
+}
+
+bool array_container_intersect(const array_container_t *array1,
+ const array_container_t *array2) {
+ int32_t card_1 = array1->cardinality, card_2 = array2->cardinality;
+ const int threshold = 64; // subject to tuning
+ if (card_1 * threshold < card_2) {
+ return intersect_skewed_uint16_nonempty(
+ array1->array, card_1, array2->array, card_2);
+ } else if (card_2 * threshold < card_1) {
+ return intersect_skewed_uint16_nonempty(
+ array2->array, card_2, array1->array, card_1);
+ } else {
+ // we do not bother vectorizing
+ return intersect_uint16_nonempty(array1->array, card_1,
+ array2->array, card_2);
+ }
+}
+
+/* computes the intersection of array1 and array2 and write the result to
+ * array1.
+ * */
+void array_container_intersection_inplace(array_container_t *src_1,
+ const array_container_t *src_2) {
+ // todo: can any of this be vectorized?
+ int32_t card_1 = src_1->cardinality, card_2 = src_2->cardinality;
+ const int threshold = 64; // subject to tuning
+ if (card_1 * threshold < card_2) {
+ src_1->cardinality = intersect_skewed_uint16(
+ src_1->array, card_1, src_2->array, card_2, src_1->array);
+ } else if (card_2 * threshold < card_1) {
+ src_1->cardinality = intersect_skewed_uint16(
+ src_2->array, card_2, src_1->array, card_1, src_1->array);
+ } else {
+ src_1->cardinality = intersect_uint16(
+ src_1->array, card_1, src_2->array, card_2, src_1->array);
+ }
+}
+
+int array_container_to_uint32_array(void *vout, const array_container_t *cont,
+ uint32_t base) {
+ int outpos = 0;
+ uint32_t *out = (uint32_t *)vout;
+ for (int i = 0; i < cont->cardinality; ++i) {
+ const uint32_t val = base + cont->array[i];
+ memcpy(out + outpos, &val,
+ sizeof(uint32_t)); // should be compiled as a MOV on x64
+ outpos++;
+ }
+ return outpos;
+}
+
+void array_container_printf(const array_container_t *v) {
+ if (v->cardinality == 0) {
+ printf("{}");
+ return;
+ }
+ printf("{");
+ printf("%d", v->array[0]);
+ for (int i = 1; i < v->cardinality; ++i) {
+ printf(",%d", v->array[i]);
+ }
+ printf("}");
+}
+
+void array_container_printf_as_uint32_array(const array_container_t *v,
+ uint32_t base) {
+ if (v->cardinality == 0) {
+ return;
+ }
+ printf("%u", v->array[0] + base);
+ for (int i = 1; i < v->cardinality; ++i) {
+ printf(",%u", v->array[i] + base);
+ }
+}
+
+/* Compute the number of runs */
+int32_t array_container_number_of_runs(const array_container_t *a) {
+ // Can SIMD work here?
+ int32_t nr_runs = 0;
+ int32_t prev = -2;
+ for (const uint16_t *p = a->array; p != a->array + a->cardinality; ++p) {
+ if (*p != prev + 1) nr_runs++;
+ prev = *p;
+ }
+ return nr_runs;
+}
+
+int32_t array_container_serialize(const array_container_t *container, char *buf) {
+ int32_t l, off;
+ uint16_t cardinality = (uint16_t)container->cardinality;
+
+ memcpy(buf, &cardinality, off = sizeof(cardinality));
+ l = sizeof(uint16_t) * container->cardinality;
+ if (l) memcpy(&buf[off], container->array, l);
+
+ return (off + l);
+}
+
+/**
+ * Writes the underlying array to buf, outputs how many bytes were written.
+ * The number of bytes written should be
+ * array_container_size_in_bytes(container).
+ *
+ */
+int32_t array_container_write(const array_container_t *container, char *buf) {
+ memcpy(buf, container->array, container->cardinality * sizeof(uint16_t));
+ return array_container_size_in_bytes(container);
+}
+
+bool array_container_is_subset(const array_container_t *container1,
+ const array_container_t *container2) {
+ if (container1->cardinality > container2->cardinality) {
+ return false;
+ }
+ int i1 = 0, i2 = 0;
+ while (i1 < container1->cardinality && i2 < container2->cardinality) {
+ if (container1->array[i1] == container2->array[i2]) {
+ i1++;
+ i2++;
+ } else if (container1->array[i1] > container2->array[i2]) {
+ i2++;
+ } else { // container1->array[i1] < container2->array[i2]
+ return false;
+ }
+ }
+ if (i1 == container1->cardinality) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int32_t array_container_read(int32_t cardinality, array_container_t *container,
+ const char *buf) {
+ if (container->capacity < cardinality) {
+ array_container_grow(container, cardinality, false);
+ }
+ container->cardinality = cardinality;
+ memcpy(container->array, buf, container->cardinality * sizeof(uint16_t));
+
+ return array_container_size_in_bytes(container);
+}
+
+uint32_t array_container_serialization_len(const array_container_t *container) {
+ return (sizeof(uint16_t) /* container->cardinality converted to 16 bit */ +
+ (sizeof(uint16_t) * container->cardinality));
+}
+
+void *array_container_deserialize(const char *buf, size_t buf_len) {
+ array_container_t *ptr;
+
+ if (buf_len < 2) /* capacity converted to 16 bit */
+ return (NULL);
+ else
+ buf_len -= 2;
+
+ if ((ptr = (array_container_t *)malloc(sizeof(array_container_t))) !=
+ NULL) {
+ size_t len;
+ int32_t off;
+ uint16_t cardinality;
+
+ memcpy(&cardinality, buf, off = sizeof(cardinality));
+
+ ptr->capacity = ptr->cardinality = (uint32_t)cardinality;
+ len = sizeof(uint16_t) * ptr->cardinality;
+
+ if (len != buf_len) {
+ free(ptr);
+ return (NULL);
+ }
+
+ if ((ptr->array = (uint16_t *)malloc(sizeof(uint16_t) *
+ ptr->capacity)) == NULL) {
+ free(ptr);
+ return (NULL);
+ }
+
+ if (len) memcpy(ptr->array, &buf[off], len);
+
+ /* Check if returned values are monotonically increasing */
+ for (int32_t i = 0, j = 0; i < ptr->cardinality; i++) {
+ if (ptr->array[i] < j) {
+ free(ptr->array);
+ free(ptr);
+ return (NULL);
+ } else
+ j = ptr->array[i];
+ }
+ }
+
+ return (ptr);
+}
+
+bool array_container_iterate(const array_container_t *cont, uint32_t base,
+ roaring_iterator iterator, void *ptr) {
+ for (int i = 0; i < cont->cardinality; i++)
+ if (!iterator(cont->array[i] + base, ptr)) return false;
+ return true;
+}
+
+bool array_container_iterate64(const array_container_t *cont, uint32_t base,
+ roaring_iterator64 iterator, uint64_t high_bits,
+ void *ptr) {
+ for (int i = 0; i < cont->cardinality; i++)
+ if (!iterator(high_bits | (uint64_t)(cont->array[i] + base), ptr))
+ return false;
+ return true;
+}
+/* end file src/containers/array.c */
+/* begin file src/containers/bitset.c */
+/*
+ * bitset.c
+ *
+ */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
+#include
+#include
+#include
+#include
+
+
+void bitset_container_clear(bitset_container_t *bitset) {
+ memset(bitset->array, 0, sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+ bitset->cardinality = 0;
+}
+
+void bitset_container_set_all(bitset_container_t *bitset) {
+ memset(bitset->array, INT64_C(-1),
+ sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+ bitset->cardinality = (1 << 16);
+}
+
+
+
+/* Create a new bitset. Return NULL in case of failure. */
+bitset_container_t *bitset_container_create(void) {
+ bitset_container_t *bitset =
+ (bitset_container_t *)malloc(sizeof(bitset_container_t));
+
+ if (!bitset) {
+ return NULL;
+ }
+ // sizeof(__m256i) == 32
+ bitset->array = (uint64_t *)roaring_bitmap_aligned_malloc(
+ 32, sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+ if (!bitset->array) {
+ free(bitset);
+ return NULL;
+ }
+ bitset_container_clear(bitset);
+ return bitset;
+}
+
+/* Copy one container into another. We assume that they are distinct. */
+void bitset_container_copy(const bitset_container_t *source,
+ bitset_container_t *dest) {
+ dest->cardinality = source->cardinality;
+ memcpy(dest->array, source->array,
+ sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+}
+
+void bitset_container_add_from_range(bitset_container_t *bitset, uint32_t min,
+ uint32_t max, uint16_t step) {
+ if (step == 0) return; // refuse to crash
+ if ((64 % step) == 0) { // step divides 64
+ uint64_t mask = 0; // construct the repeated mask
+ for (uint32_t value = (min % step); value < 64; value += step) {
+ mask |= ((uint64_t)1 << value);
+ }
+ uint32_t firstword = min / 64;
+ uint32_t endword = (max - 1) / 64;
+ bitset->cardinality = (max - min + step - 1) / step;
+ if (firstword == endword) {
+ bitset->array[firstword] |=
+ mask & (((~UINT64_C(0)) << (min % 64)) &
+ ((~UINT64_C(0)) >> ((~max + 1) % 64)));
+ return;
+ }
+ bitset->array[firstword] = mask & ((~UINT64_C(0)) << (min % 64));
+ for (uint32_t i = firstword + 1; i < endword; i++)
+ bitset->array[i] = mask;
+ bitset->array[endword] = mask & ((~UINT64_C(0)) >> ((~max + 1) % 64));
+ } else {
+ for (uint32_t value = min; value < max; value += step) {
+ bitset_container_add(bitset, value);
+ }
+ }
+}
+
+/* Free memory. */
+void bitset_container_free(bitset_container_t *bitset) {
+ if(bitset->array != NULL) {// Jon Strabala reports that some tools complain otherwise
+ roaring_bitmap_aligned_free(bitset->array);
+ bitset->array = NULL; // pedantic
+ }
+ free(bitset);
+}
+
+/* duplicate container. */
+bitset_container_t *bitset_container_clone(const bitset_container_t *src) {
+ bitset_container_t *bitset =
+ (bitset_container_t *)malloc(sizeof(bitset_container_t));
+ assert(bitset);
+
+ // sizeof(__m256i) == 32
+ bitset->array = (uint64_t *)roaring_bitmap_aligned_malloc(
+ 32, sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+ assert(bitset->array);
+ bitset->cardinality = src->cardinality;
+ memcpy(bitset->array, src->array,
+ sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+ return bitset;
+}
+
+void bitset_container_set_range(bitset_container_t *bitset, uint32_t begin,
+ uint32_t end) {
+ bitset_set_range(bitset->array, begin, end);
+ bitset->cardinality =
+ bitset_container_compute_cardinality(bitset); // could be smarter
+}
+
+
+bool bitset_container_intersect(const bitset_container_t *src_1,
+ const bitset_container_t *src_2) {
+ // could vectorize, but this is probably already quite fast in practice
+ const uint64_t * __restrict__ array_1 = src_1->array;
+ const uint64_t * __restrict__ array_2 = src_2->array;
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i ++) {
+ if((array_1[i] & array_2[i]) != 0) return true;
+ }
+ return false;
+}
+
+
+#ifdef USEAVX
+#ifndef WORDS_IN_AVX2_REG
+#define WORDS_IN_AVX2_REG sizeof(__m256i) / sizeof(uint64_t)
+#endif
+/* Get the number of bits set (force computation) */
+int bitset_container_compute_cardinality(const bitset_container_t *bitset) {
+ return (int) avx2_harley_seal_popcount256(
+ (const __m256i *)bitset->array,
+ BITSET_CONTAINER_SIZE_IN_WORDS / (WORDS_IN_AVX2_REG));
+}
+
+#elif defined(USENEON)
+int bitset_container_compute_cardinality(const bitset_container_t *bitset) {
+ uint16x8_t n0 = vdupq_n_u16(0);
+ uint16x8_t n1 = vdupq_n_u16(0);
+ uint16x8_t n2 = vdupq_n_u16(0);
+ uint16x8_t n3 = vdupq_n_u16(0);
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 8) {
+ uint64x2_t c0 = vld1q_u64(&bitset->array[i + 0]);
+ n0 = vaddq_u16(n0, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c0))));
+ uint64x2_t c1 = vld1q_u64(&bitset->array[i + 2]);
+ n1 = vaddq_u16(n1, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c1))));
+ uint64x2_t c2 = vld1q_u64(&bitset->array[i + 4]);
+ n2 = vaddq_u16(n2, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c2))));
+ uint64x2_t c3 = vld1q_u64(&bitset->array[i + 6]);
+ n3 = vaddq_u16(n3, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c3))));
+ }
+ uint64x2_t n = vdupq_n_u64(0);
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n0)));
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n1)));
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n2)));
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n3)));
+ return vgetq_lane_u64(n, 0) + vgetq_lane_u64(n, 1);
+}
+
+#else
+
+/* Get the number of bits set (force computation) */
+int bitset_container_compute_cardinality(const bitset_container_t *bitset) {
+ const uint64_t *array = bitset->array;
+ int32_t sum = 0;
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 4) {
+ sum += hamming(array[i]);
+ sum += hamming(array[i + 1]);
+ sum += hamming(array[i + 2]);
+ sum += hamming(array[i + 3]);
+ }
+ return sum;
+}
+
+#endif
+
+#ifdef USEAVX
+
+#define BITSET_CONTAINER_FN_REPEAT 8
+#ifndef WORDS_IN_AVX2_REG
+#define WORDS_IN_AVX2_REG sizeof(__m256i) / sizeof(uint64_t)
+#endif
+#define LOOP_SIZE \
+ BITSET_CONTAINER_SIZE_IN_WORDS / \
+ ((WORDS_IN_AVX2_REG)*BITSET_CONTAINER_FN_REPEAT)
+
+/* Computes a binary operation (eg union) on bitset1 and bitset2 and write the
+ result to bitsetout */
+// clang-format off
+#define BITSET_CONTAINER_FN(opname, opsymbol, avx_intrinsic, neon_intrinsic) \
+int bitset_container_##opname##_nocard(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2, \
+ bitset_container_t *dst) { \
+ const uint8_t * __restrict__ array_1 = (const uint8_t *)src_1->array; \
+ const uint8_t * __restrict__ array_2 = (const uint8_t *)src_2->array; \
+ /* not using the blocking optimization for some reason*/ \
+ uint8_t *out = (uint8_t*)dst->array; \
+ const int innerloop = 8; \
+ for (size_t i = 0; \
+ i < BITSET_CONTAINER_SIZE_IN_WORDS / (WORDS_IN_AVX2_REG); \
+ i+=innerloop) {\
+ __m256i A1, A2, AO; \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)out, AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 32)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 32)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+32), AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 64)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 64)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+64), AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 96)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 96)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+96), AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 128)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 128)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+128), AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 160)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 160)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+160), AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 192)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 192)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+192), AO); \
+ A1 = _mm256_lddqu_si256((const __m256i *)(array_1 + 224)); \
+ A2 = _mm256_lddqu_si256((const __m256i *)(array_2 + 224)); \
+ AO = avx_intrinsic(A2, A1); \
+ _mm256_storeu_si256((__m256i *)(out+224), AO); \
+ out+=256; \
+ array_1 += 256; \
+ array_2 += 256; \
+ } \
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY; \
+ return dst->cardinality; \
+} \
+/* next, a version that updates cardinality*/ \
+int bitset_container_##opname(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2, \
+ bitset_container_t *dst) { \
+ const __m256i * __restrict__ array_1 = (const __m256i *) src_1->array; \
+ const __m256i * __restrict__ array_2 = (const __m256i *) src_2->array; \
+ __m256i *out = (__m256i *) dst->array; \
+ dst->cardinality = (int32_t)avx2_harley_seal_popcount256andstore_##opname(array_2,\
+ array_1, out,BITSET_CONTAINER_SIZE_IN_WORDS / (WORDS_IN_AVX2_REG));\
+ return dst->cardinality; \
+} \
+/* next, a version that just computes the cardinality*/ \
+int bitset_container_##opname##_justcard(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2) { \
+ const __m256i * __restrict__ data1 = (const __m256i *) src_1->array; \
+ const __m256i * __restrict__ data2 = (const __m256i *) src_2->array; \
+ return (int)avx2_harley_seal_popcount256_##opname(data2, \
+ data1, BITSET_CONTAINER_SIZE_IN_WORDS / (WORDS_IN_AVX2_REG));\
+}
+
+#elif defined(USENEON)
+
+#define BITSET_CONTAINER_FN(opname, opsymbol, avx_intrinsic, neon_intrinsic) \
+int bitset_container_##opname(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2, \
+ bitset_container_t *dst) { \
+ const uint64_t * __restrict__ array_1 = src_1->array; \
+ const uint64_t * __restrict__ array_2 = src_2->array; \
+ uint64_t *out = dst->array; \
+ uint16x8_t n0 = vdupq_n_u16(0); \
+ uint16x8_t n1 = vdupq_n_u16(0); \
+ uint16x8_t n2 = vdupq_n_u16(0); \
+ uint16x8_t n3 = vdupq_n_u16(0); \
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 8) { \
+ uint64x2_t c0 = neon_intrinsic(vld1q_u64(&array_1[i + 0]), \
+ vld1q_u64(&array_2[i + 0])); \
+ n0 = vaddq_u16(n0, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c0)))); \
+ vst1q_u64(&out[i + 0], c0); \
+ uint64x2_t c1 = neon_intrinsic(vld1q_u64(&array_1[i + 2]), \
+ vld1q_u64(&array_2[i + 2])); \
+ n1 = vaddq_u16(n1, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c1)))); \
+ vst1q_u64(&out[i + 2], c1); \
+ uint64x2_t c2 = neon_intrinsic(vld1q_u64(&array_1[i + 4]), \
+ vld1q_u64(&array_2[i + 4])); \
+ n2 = vaddq_u16(n2, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c2)))); \
+ vst1q_u64(&out[i + 4], c2); \
+ uint64x2_t c3 = neon_intrinsic(vld1q_u64(&array_1[i + 6]), \
+ vld1q_u64(&array_2[i + 6])); \
+ n3 = vaddq_u16(n3, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c3)))); \
+ vst1q_u64(&out[i + 6], c3); \
+ } \
+ uint64x2_t n = vdupq_n_u64(0); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n0))); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n1))); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n2))); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n3))); \
+ dst->cardinality = vgetq_lane_u64(n, 0) + vgetq_lane_u64(n, 1); \
+ return dst->cardinality; \
+} \
+int bitset_container_##opname##_nocard(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2, \
+ bitset_container_t *dst) { \
+ const uint64_t * __restrict__ array_1 = src_1->array; \
+ const uint64_t * __restrict__ array_2 = src_2->array; \
+ uint64_t *out = dst->array; \
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 8) { \
+ vst1q_u64(&out[i + 0], neon_intrinsic(vld1q_u64(&array_1[i + 0]), \
+ vld1q_u64(&array_2[i + 0]))); \
+ vst1q_u64(&out[i + 2], neon_intrinsic(vld1q_u64(&array_1[i + 2]), \
+ vld1q_u64(&array_2[i + 2]))); \
+ vst1q_u64(&out[i + 4], neon_intrinsic(vld1q_u64(&array_1[i + 4]), \
+ vld1q_u64(&array_2[i + 4]))); \
+ vst1q_u64(&out[i + 6], neon_intrinsic(vld1q_u64(&array_1[i + 6]), \
+ vld1q_u64(&array_2[i + 6]))); \
+ } \
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY; \
+ return dst->cardinality; \
+} \
+int bitset_container_##opname##_justcard(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2) { \
+ const uint64_t * __restrict__ array_1 = src_1->array; \
+ const uint64_t * __restrict__ array_2 = src_2->array; \
+ uint16x8_t n0 = vdupq_n_u16(0); \
+ uint16x8_t n1 = vdupq_n_u16(0); \
+ uint16x8_t n2 = vdupq_n_u16(0); \
+ uint16x8_t n3 = vdupq_n_u16(0); \
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 8) { \
+ uint64x2_t c0 = neon_intrinsic(vld1q_u64(&array_1[i + 0]), \
+ vld1q_u64(&array_2[i + 0])); \
+ n0 = vaddq_u16(n0, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c0)))); \
+ uint64x2_t c1 = neon_intrinsic(vld1q_u64(&array_1[i + 2]), \
+ vld1q_u64(&array_2[i + 2])); \
+ n1 = vaddq_u16(n1, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c1)))); \
+ uint64x2_t c2 = neon_intrinsic(vld1q_u64(&array_1[i + 4]), \
+ vld1q_u64(&array_2[i + 4])); \
+ n2 = vaddq_u16(n2, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c2)))); \
+ uint64x2_t c3 = neon_intrinsic(vld1q_u64(&array_1[i + 6]), \
+ vld1q_u64(&array_2[i + 6])); \
+ n3 = vaddq_u16(n3, vpaddlq_u8(vcntq_u8(vreinterpretq_u8_u64(c3)))); \
+ } \
+ uint64x2_t n = vdupq_n_u64(0); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n0))); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n1))); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n2))); \
+ n = vaddq_u64(n, vpaddlq_u32(vpaddlq_u16(n3))); \
+ return vgetq_lane_u64(n, 0) + vgetq_lane_u64(n, 1); \
+}
+
+#else /* not USEAVX */
+
+#define BITSET_CONTAINER_FN(opname, opsymbol, avx_intrinsic, neon_intrinsic) \
+int bitset_container_##opname(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2, \
+ bitset_container_t *dst) { \
+ const uint64_t * __restrict__ array_1 = src_1->array; \
+ const uint64_t * __restrict__ array_2 = src_2->array; \
+ uint64_t *out = dst->array; \
+ int32_t sum = 0; \
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 2) { \
+ const uint64_t word_1 = (array_1[i])opsymbol(array_2[i]), \
+ word_2 = (array_1[i + 1])opsymbol(array_2[i + 1]); \
+ out[i] = word_1; \
+ out[i + 1] = word_2; \
+ sum += hamming(word_1); \
+ sum += hamming(word_2); \
+ } \
+ dst->cardinality = sum; \
+ return dst->cardinality; \
+} \
+int bitset_container_##opname##_nocard(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2, \
+ bitset_container_t *dst) { \
+ const uint64_t * __restrict__ array_1 = src_1->array; \
+ const uint64_t * __restrict__ array_2 = src_2->array; \
+ uint64_t *out = dst->array; \
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i++) { \
+ out[i] = (array_1[i])opsymbol(array_2[i]); \
+ } \
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY; \
+ return dst->cardinality; \
+} \
+int bitset_container_##opname##_justcard(const bitset_container_t *src_1, \
+ const bitset_container_t *src_2) { \
+ const uint64_t * __restrict__ array_1 = src_1->array; \
+ const uint64_t * __restrict__ array_2 = src_2->array; \
+ int32_t sum = 0; \
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 2) { \
+ const uint64_t word_1 = (array_1[i])opsymbol(array_2[i]), \
+ word_2 = (array_1[i + 1])opsymbol(array_2[i + 1]); \
+ sum += hamming(word_1); \
+ sum += hamming(word_2); \
+ } \
+ return sum; \
+}
+
+#endif
+
+// we duplicate the function because other containers use the "or" term, makes API more consistent
+BITSET_CONTAINER_FN(or, |, _mm256_or_si256, vorrq_u64)
+BITSET_CONTAINER_FN(union, |, _mm256_or_si256, vorrq_u64)
+
+// we duplicate the function because other containers use the "intersection" term, makes API more consistent
+BITSET_CONTAINER_FN(and, &, _mm256_and_si256, vandq_u64)
+BITSET_CONTAINER_FN(intersection, &, _mm256_and_si256, vandq_u64)
+
+BITSET_CONTAINER_FN(xor, ^, _mm256_xor_si256, veorq_u64)
+BITSET_CONTAINER_FN(andnot, &~, _mm256_andnot_si256, vbicq_u64)
+// clang-format On
+
+
+
+int bitset_container_to_uint32_array( void *vout, const bitset_container_t *cont, uint32_t base) {
+#ifdef USEAVX2FORDECODING
+ if(cont->cardinality >= 8192)// heuristic
+ return (int) bitset_extract_setbits_avx2(cont->array, BITSET_CONTAINER_SIZE_IN_WORDS, vout,cont->cardinality,base);
+ else
+ return (int) bitset_extract_setbits(cont->array, BITSET_CONTAINER_SIZE_IN_WORDS, vout,base);
+#else
+ return (int) bitset_extract_setbits(cont->array, BITSET_CONTAINER_SIZE_IN_WORDS, vout,base);
+#endif
+}
+
+/*
+ * Print this container using printf (useful for debugging).
+ */
+void bitset_container_printf(const bitset_container_t * v) {
+ printf("{");
+ uint32_t base = 0;
+ bool iamfirst = true;// TODO: rework so that this is not necessary yet still readable
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i) {
+ uint64_t w = v->array[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ if(iamfirst) {// predicted to be false
+ printf("%u",base + r);
+ iamfirst = false;
+ } else {
+ printf(",%u",base + r);
+ }
+ w ^= t;
+ }
+ base += 64;
+ }
+ printf("}");
+}
+
+
+/*
+ * Print this container using printf as a comma-separated list of 32-bit integers starting at base.
+ */
+void bitset_container_printf_as_uint32_array(const bitset_container_t * v, uint32_t base) {
+ bool iamfirst = true;// TODO: rework so that this is not necessary yet still readable
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i) {
+ uint64_t w = v->array[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ if(iamfirst) {// predicted to be false
+ printf("%u", r + base);
+ iamfirst = false;
+ } else {
+ printf(",%u",r + base);
+ }
+ w ^= t;
+ }
+ base += 64;
+ }
+}
+
+
+// TODO: use the fast lower bound, also
+int bitset_container_number_of_runs(bitset_container_t *b) {
+ int num_runs = 0;
+ uint64_t next_word = b->array[0];
+
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS-1; ++i) {
+ uint64_t word = next_word;
+ next_word = b->array[i+1];
+ num_runs += hamming((~word) & (word << 1)) + ( (word >> 63) & ~next_word);
+ }
+
+ uint64_t word = next_word;
+ num_runs += hamming((~word) & (word << 1));
+ if((word & 0x8000000000000000ULL) != 0)
+ num_runs++;
+ return num_runs;
+}
+
+int32_t bitset_container_serialize(const bitset_container_t *container, char *buf) {
+ int32_t l = sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS;
+ memcpy(buf, container->array, l);
+ return(l);
+}
+
+
+
+int32_t bitset_container_write(const bitset_container_t *container,
+ char *buf) {
+ memcpy(buf, container->array, BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t));
+ return bitset_container_size_in_bytes(container);
+}
+
+
+int32_t bitset_container_read(int32_t cardinality, bitset_container_t *container,
+ const char *buf) {
+ container->cardinality = cardinality;
+ memcpy(container->array, buf, BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t));
+ return bitset_container_size_in_bytes(container);
+}
+
+uint32_t bitset_container_serialization_len(void) {
+ return(sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS);
+}
+
+void* bitset_container_deserialize(const char *buf, size_t buf_len) {
+ bitset_container_t *ptr;
+ size_t l = sizeof(uint64_t) * BITSET_CONTAINER_SIZE_IN_WORDS;
+
+ if(l != buf_len)
+ return(NULL);
+
+ if((ptr = (bitset_container_t *)malloc(sizeof(bitset_container_t))) != NULL) {
+ memcpy(ptr, buf, sizeof(bitset_container_t));
+ // sizeof(__m256i) == 32
+ ptr->array = (uint64_t *) roaring_bitmap_aligned_malloc(32, l);
+ if (! ptr->array) {
+ free(ptr);
+ return NULL;
+ }
+ memcpy(ptr->array, buf, l);
+ ptr->cardinality = bitset_container_compute_cardinality(ptr);
+ }
+
+ return((void*)ptr);
+}
+
+bool bitset_container_iterate(const bitset_container_t *cont, uint32_t base, roaring_iterator iterator, void *ptr) {
+ for (int32_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i ) {
+ uint64_t w = cont->array[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ if(!iterator(r + base, ptr)) return false;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return true;
+}
+
+bool bitset_container_iterate64(const bitset_container_t *cont, uint32_t base, roaring_iterator64 iterator, uint64_t high_bits, void *ptr) {
+ for (int32_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i ) {
+ uint64_t w = cont->array[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ if(!iterator(high_bits | (uint64_t)(r + base), ptr)) return false;
+ w ^= t;
+ }
+ base += 64;
+ }
+ return true;
+}
+
+
+bool bitset_container_equals(const bitset_container_t *container1, const bitset_container_t *container2) {
+ if((container1->cardinality != BITSET_UNKNOWN_CARDINALITY) && (container2->cardinality != BITSET_UNKNOWN_CARDINALITY)) {
+ if(container1->cardinality != container2->cardinality) {
+ return false;
+ }
+ if (container1->cardinality == INT32_C(0x10000)) {
+ return true;
+ }
+ }
+#ifdef USEAVX
+ const __m256i *ptr1 = (const __m256i*)container1->array;
+ const __m256i *ptr2 = (const __m256i*)container2->array;
+ for (size_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS*sizeof(uint64_t)/32; i++) {
+ __m256i r1 = _mm256_load_si256(ptr1+i);
+ __m256i r2 = _mm256_load_si256(ptr2+i);
+ int mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(r1, r2));
+ if ((uint32_t)mask != UINT32_MAX) {
+ return false;
+ }
+ }
+#else
+ return memcmp(container1->array,
+ container2->array,
+ BITSET_CONTAINER_SIZE_IN_WORDS*sizeof(uint64_t)) == 0;
+#endif
+ return true;
+}
+
+bool bitset_container_is_subset(const bitset_container_t *container1,
+ const bitset_container_t *container2) {
+ if((container1->cardinality != BITSET_UNKNOWN_CARDINALITY) && (container2->cardinality != BITSET_UNKNOWN_CARDINALITY)) {
+ if(container1->cardinality > container2->cardinality) {
+ return false;
+ }
+ }
+ for(int32_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i ) {
+ if((container1->array[i] & container2->array[i]) != container1->array[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool bitset_container_select(const bitset_container_t *container, uint32_t *start_rank, uint32_t rank, uint32_t *element) {
+ int card = bitset_container_cardinality(container);
+ if(rank >= *start_rank + card) {
+ *start_rank += card;
+ return false;
+ }
+ const uint64_t *array = container->array;
+ int32_t size;
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i += 1) {
+ size = hamming(array[i]);
+ if(rank <= *start_rank + size) {
+ uint64_t w = container->array[i];
+ uint16_t base = i*64;
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ int r = __builtin_ctzll(w);
+ if(*start_rank == rank) {
+ *element = r+base;
+ return true;
+ }
+ w ^= t;
+ *start_rank += 1;
+ }
+ }
+ else
+ *start_rank += size;
+ }
+ assert(false);
+ __builtin_unreachable();
+}
+
+
+/* Returns the smallest value (assumes not empty) */
+uint16_t bitset_container_minimum(const bitset_container_t *container) {
+ for (int32_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i ) {
+ uint64_t w = container->array[i];
+ if (w != 0) {
+ int r = __builtin_ctzll(w);
+ return r + i * 64;
+ }
+ }
+ return UINT16_MAX;
+}
+
+/* Returns the largest value (assumes not empty) */
+uint16_t bitset_container_maximum(const bitset_container_t *container) {
+ for (int32_t i = BITSET_CONTAINER_SIZE_IN_WORDS - 1; i > 0; --i ) {
+ uint64_t w = container->array[i];
+ if (w != 0) {
+ int r = __builtin_clzll(w);
+ return i * 64 + 63 - r;
+ }
+ }
+ return 0;
+}
+
+/* Returns the number of values equal or smaller than x */
+int bitset_container_rank(const bitset_container_t *container, uint16_t x) {
+ // credit: aqrit
+ int sum = 0;
+ int i = 0;
+ for (int end = x / 64; i < end; i++){
+ sum += hamming(container->array[i]);
+ }
+ uint64_t lastword = container->array[i];
+ uint64_t lastpos = UINT64_C(1) << (x % 64);
+ uint64_t mask = lastpos + lastpos - 1; // smear right
+ sum += hamming(lastword & mask);
+ return sum;
+}
+
+/* Returns the index of the first value equal or larger than x, or -1 */
+int bitset_container_index_equalorlarger(const bitset_container_t *container, uint16_t x) {
+ uint32_t x32 = x;
+ uint32_t k = x32 / 64;
+ uint64_t word = container->array[k];
+ const int diff = x32 - k * 64; // in [0,64)
+ word = (word >> diff) << diff; // a mask is faster, but we don't care
+ while(word == 0) {
+ k++;
+ if(k == BITSET_CONTAINER_SIZE_IN_WORDS) return -1;
+ word = container->array[k];
+ }
+ return k * 64 + __builtin_ctzll(word);
+}
+/* end file src/containers/bitset.c */
+/* begin file src/containers/containers.c */
+
+
+void container_free(void *container, uint8_t typecode) {
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ bitset_container_free((bitset_container_t *)container);
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ array_container_free((array_container_t *)container);
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ run_container_free((run_container_t *)container);
+ break;
+ case SHARED_CONTAINER_TYPE_CODE:
+ shared_container_free((shared_container_t *)container);
+ break;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ }
+}
+
+void container_printf(const void *container, uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ bitset_container_printf((const bitset_container_t *)container);
+ return;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ array_container_printf((const array_container_t *)container);
+ return;
+ case RUN_CONTAINER_TYPE_CODE:
+ run_container_printf((const run_container_t *)container);
+ return;
+ default:
+ __builtin_unreachable();
+ }
+}
+
+void container_printf_as_uint32_array(const void *container, uint8_t typecode,
+ uint32_t base) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ bitset_container_printf_as_uint32_array(
+ (const bitset_container_t *)container, base);
+ return;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ array_container_printf_as_uint32_array(
+ (const array_container_t *)container, base);
+ return;
+ case RUN_CONTAINER_TYPE_CODE:
+ run_container_printf_as_uint32_array(
+ (const run_container_t *)container, base);
+ return;
+ return;
+ default:
+ __builtin_unreachable();
+ }
+}
+
+int32_t container_serialize(const void *container, uint8_t typecode,
+ char *buf) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return (bitset_container_serialize((const bitset_container_t *)container,
+ buf));
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return (
+ array_container_serialize((const array_container_t *)container, buf));
+ case RUN_CONTAINER_TYPE_CODE:
+ return (run_container_serialize((const run_container_t *)container, buf));
+ default:
+ assert(0);
+ __builtin_unreachable();
+ return (-1);
+ }
+}
+
+uint32_t container_serialization_len(const void *container, uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_serialization_len();
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_serialization_len(
+ (const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_serialization_len(
+ (const run_container_t *)container);
+ default:
+ assert(0);
+ __builtin_unreachable();
+ return (0);
+ }
+}
+
+void *container_deserialize(uint8_t typecode, const char *buf, size_t buf_len) {
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return (bitset_container_deserialize(buf, buf_len));
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return (array_container_deserialize(buf, buf_len));
+ case RUN_CONTAINER_TYPE_CODE:
+ return (run_container_deserialize(buf, buf_len));
+ case SHARED_CONTAINER_TYPE_CODE:
+ printf("this should never happen.\n");
+ assert(0);
+ __builtin_unreachable();
+ return (NULL);
+ default:
+ assert(0);
+ __builtin_unreachable();
+ return (NULL);
+ }
+}
+
+void *get_copy_of_container(void *container, uint8_t *typecode,
+ bool copy_on_write) {
+ if (copy_on_write) {
+ shared_container_t *shared_container;
+ if (*typecode == SHARED_CONTAINER_TYPE_CODE) {
+ shared_container = (shared_container_t *)container;
+ shared_container->counter += 1;
+ return shared_container;
+ }
+ assert(*typecode != SHARED_CONTAINER_TYPE_CODE);
+
+ if ((shared_container = (shared_container_t *)malloc(
+ sizeof(shared_container_t))) == NULL) {
+ return NULL;
+ }
+
+ shared_container->container = container;
+ shared_container->typecode = *typecode;
+
+ shared_container->counter = 2;
+ *typecode = SHARED_CONTAINER_TYPE_CODE;
+
+ return shared_container;
+ } // copy_on_write
+ // otherwise, no copy on write...
+ const void *actualcontainer =
+ container_unwrap_shared((const void *)container, typecode);
+ assert(*typecode != SHARED_CONTAINER_TYPE_CODE);
+ return container_clone(actualcontainer, *typecode);
+}
+/**
+ * Copies a container, requires a typecode. This allocates new memory, caller
+ * is responsible for deallocation.
+ */
+void *container_clone(const void *container, uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_clone((const bitset_container_t *)container);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_clone((const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_clone((const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ printf("shared containers are not clonable\n");
+ assert(false);
+ return NULL;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+void *shared_container_extract_copy(shared_container_t *container,
+ uint8_t *typecode) {
+ assert(container->counter > 0);
+ assert(container->typecode != SHARED_CONTAINER_TYPE_CODE);
+ container->counter--;
+ *typecode = container->typecode;
+ void *answer;
+ if (container->counter == 0) {
+ answer = container->container;
+ container->container = NULL; // paranoid
+ free(container);
+ } else {
+ answer = container_clone(container->container, *typecode);
+ }
+ assert(*typecode != SHARED_CONTAINER_TYPE_CODE);
+ return answer;
+}
+
+void shared_container_free(shared_container_t *container) {
+ assert(container->counter > 0);
+ container->counter--;
+ if (container->counter == 0) {
+ assert(container->typecode != SHARED_CONTAINER_TYPE_CODE);
+ container_free(container->container, container->typecode);
+ container->container = NULL; // paranoid
+ free(container);
+ }
+}
+
+/* end file src/containers/containers.c */
+/* begin file src/containers/convert.c */
+#include
+
+
+// file contains grubby stuff that must know impl. details of all container
+// types.
+bitset_container_t *bitset_container_from_array(const array_container_t *a) {
+ bitset_container_t *ans = bitset_container_create();
+ int limit = array_container_cardinality(a);
+ for (int i = 0; i < limit; ++i) bitset_container_set(ans, a->array[i]);
+ return ans;
+}
+
+bitset_container_t *bitset_container_from_run(const run_container_t *arr) {
+ int card = run_container_cardinality(arr);
+ bitset_container_t *answer = bitset_container_create();
+ for (int rlepos = 0; rlepos < arr->n_runs; ++rlepos) {
+ rle16_t vl = arr->runs[rlepos];
+ bitset_set_lenrange(answer->array, vl.value, vl.length);
+ }
+ answer->cardinality = card;
+ return answer;
+}
+
+array_container_t *array_container_from_run(const run_container_t *arr) {
+ array_container_t *answer =
+ array_container_create_given_capacity(run_container_cardinality(arr));
+ answer->cardinality = 0;
+ for (int rlepos = 0; rlepos < arr->n_runs; ++rlepos) {
+ int run_start = arr->runs[rlepos].value;
+ int run_end = run_start + arr->runs[rlepos].length;
+
+ for (int run_value = run_start; run_value <= run_end; ++run_value) {
+ answer->array[answer->cardinality++] = (uint16_t)run_value;
+ }
+ }
+ return answer;
+}
+
+array_container_t *array_container_from_bitset(const bitset_container_t *bits) {
+ array_container_t *result =
+ array_container_create_given_capacity(bits->cardinality);
+ result->cardinality = bits->cardinality;
+ // sse version ends up being slower here
+ // (bitset_extract_setbits_sse_uint16)
+ // because of the sparsity of the data
+ bitset_extract_setbits_uint16(bits->array, BITSET_CONTAINER_SIZE_IN_WORDS,
+ result->array, 0);
+ return result;
+}
+
+/* assumes that container has adequate space. Run from [s,e] (inclusive) */
+static void add_run(run_container_t *r, int s, int e) {
+ r->runs[r->n_runs].value = s;
+ r->runs[r->n_runs].length = e - s;
+ r->n_runs++;
+}
+
+run_container_t *run_container_from_array(const array_container_t *c) {
+ int32_t n_runs = array_container_number_of_runs(c);
+ run_container_t *answer = run_container_create_given_capacity(n_runs);
+ int prev = -2;
+ int run_start = -1;
+ int32_t card = c->cardinality;
+ if (card == 0) return answer;
+ for (int i = 0; i < card; ++i) {
+ const uint16_t cur_val = c->array[i];
+ if (cur_val != prev + 1) {
+ // new run starts; flush old one, if any
+ if (run_start != -1) add_run(answer, run_start, prev);
+ run_start = cur_val;
+ }
+ prev = c->array[i];
+ }
+ // now prev is the last seen value
+ add_run(answer, run_start, prev);
+ // assert(run_container_cardinality(answer) == c->cardinality);
+ return answer;
+}
+
+/**
+ * Convert the runcontainer to either a Bitmap or an Array Container, depending
+ * on the cardinality. Frees the container.
+ * Allocates and returns new container, which caller is responsible for freeing.
+ * It does not free the run container.
+ */
+
+void *convert_to_bitset_or_array_container(run_container_t *r, int32_t card,
+ uint8_t *resulttype) {
+ if (card <= DEFAULT_MAX_SIZE) {
+ array_container_t *answer = array_container_create_given_capacity(card);
+ answer->cardinality = 0;
+ for (int rlepos = 0; rlepos < r->n_runs; ++rlepos) {
+ uint16_t run_start = r->runs[rlepos].value;
+ uint16_t run_end = run_start + r->runs[rlepos].length;
+ for (uint16_t run_value = run_start; run_value <= run_end;
+ ++run_value) {
+ answer->array[answer->cardinality++] = run_value;
+ }
+ }
+ assert(card == answer->cardinality);
+ *resulttype = ARRAY_CONTAINER_TYPE_CODE;
+ //run_container_free(r);
+ return answer;
+ }
+ bitset_container_t *answer = bitset_container_create();
+ for (int rlepos = 0; rlepos < r->n_runs; ++rlepos) {
+ uint16_t run_start = r->runs[rlepos].value;
+ bitset_set_lenrange(answer->array, run_start, r->runs[rlepos].length);
+ }
+ answer->cardinality = card;
+ *resulttype = BITSET_CONTAINER_TYPE_CODE;
+ //run_container_free(r);
+ return answer;
+}
+
+/* Converts a run container to either an array or a bitset, IF it saves space.
+ */
+/* If a conversion occurs, the caller is responsible to free the original
+ * container and
+ * he becomes responsible to free the new one. */
+void *convert_run_to_efficient_container(run_container_t *c,
+ uint8_t *typecode_after) {
+ int32_t size_as_run_container =
+ run_container_serialized_size_in_bytes(c->n_runs);
+
+ int32_t size_as_bitset_container =
+ bitset_container_serialized_size_in_bytes();
+ int32_t card = run_container_cardinality(c);
+ int32_t size_as_array_container =
+ array_container_serialized_size_in_bytes(card);
+
+ int32_t min_size_non_run =
+ size_as_bitset_container < size_as_array_container
+ ? size_as_bitset_container
+ : size_as_array_container;
+ if (size_as_run_container <= min_size_non_run) { // no conversion
+ *typecode_after = RUN_CONTAINER_TYPE_CODE;
+ return c;
+ }
+ if (card <= DEFAULT_MAX_SIZE) {
+ // to array
+ array_container_t *answer = array_container_create_given_capacity(card);
+ answer->cardinality = 0;
+ for (int rlepos = 0; rlepos < c->n_runs; ++rlepos) {
+ int run_start = c->runs[rlepos].value;
+ int run_end = run_start + c->runs[rlepos].length;
+
+ for (int run_value = run_start; run_value <= run_end; ++run_value) {
+ answer->array[answer->cardinality++] = (uint16_t)run_value;
+ }
+ }
+ *typecode_after = ARRAY_CONTAINER_TYPE_CODE;
+ return answer;
+ }
+
+ // else to bitset
+ bitset_container_t *answer = bitset_container_create();
+
+ for (int rlepos = 0; rlepos < c->n_runs; ++rlepos) {
+ int start = c->runs[rlepos].value;
+ int end = start + c->runs[rlepos].length;
+ bitset_set_range(answer->array, start, end + 1);
+ }
+ answer->cardinality = card;
+ *typecode_after = BITSET_CONTAINER_TYPE_CODE;
+ return answer;
+}
+
+// like convert_run_to_efficient_container but frees the old result if needed
+void *convert_run_to_efficient_container_and_free(run_container_t *c,
+ uint8_t *typecode_after) {
+ void *answer = convert_run_to_efficient_container(c, typecode_after);
+ if (answer != c) run_container_free(c);
+ return answer;
+}
+
+/* once converted, the original container is disposed here, rather than
+ in roaring_array
+*/
+
+// TODO: split into run- array- and bitset- subfunctions for sanity;
+// a few function calls won't really matter.
+
+void *convert_run_optimize(void *c, uint8_t typecode_original,
+ uint8_t *typecode_after) {
+ if (typecode_original == RUN_CONTAINER_TYPE_CODE) {
+ void *newc = convert_run_to_efficient_container((run_container_t *)c,
+ typecode_after);
+ if (newc != c) {
+ container_free(c, typecode_original);
+ }
+ return newc;
+ } else if (typecode_original == ARRAY_CONTAINER_TYPE_CODE) {
+ // it might need to be converted to a run container.
+ array_container_t *c_qua_array = (array_container_t *)c;
+ int32_t n_runs = array_container_number_of_runs(c_qua_array);
+ int32_t size_as_run_container =
+ run_container_serialized_size_in_bytes(n_runs);
+ int32_t card = array_container_cardinality(c_qua_array);
+ int32_t size_as_array_container =
+ array_container_serialized_size_in_bytes(card);
+
+ if (size_as_run_container >= size_as_array_container) {
+ *typecode_after = ARRAY_CONTAINER_TYPE_CODE;
+ return c;
+ }
+ // else convert array to run container
+ run_container_t *answer = run_container_create_given_capacity(n_runs);
+ int prev = -2;
+ int run_start = -1;
+
+ assert(card > 0);
+ for (int i = 0; i < card; ++i) {
+ uint16_t cur_val = c_qua_array->array[i];
+ if (cur_val != prev + 1) {
+ // new run starts; flush old one, if any
+ if (run_start != -1) add_run(answer, run_start, prev);
+ run_start = cur_val;
+ }
+ prev = c_qua_array->array[i];
+ }
+ assert(run_start >= 0);
+ // now prev is the last seen value
+ add_run(answer, run_start, prev);
+ *typecode_after = RUN_CONTAINER_TYPE_CODE;
+ array_container_free(c_qua_array);
+ return answer;
+ } else if (typecode_original ==
+ BITSET_CONTAINER_TYPE_CODE) { // run conversions on bitset
+ // does bitset need conversion to run?
+ bitset_container_t *c_qua_bitset = (bitset_container_t *)c;
+ int32_t n_runs = bitset_container_number_of_runs(c_qua_bitset);
+ int32_t size_as_run_container =
+ run_container_serialized_size_in_bytes(n_runs);
+ int32_t size_as_bitset_container =
+ bitset_container_serialized_size_in_bytes();
+
+ if (size_as_bitset_container <= size_as_run_container) {
+ // no conversion needed.
+ *typecode_after = BITSET_CONTAINER_TYPE_CODE;
+ return c;
+ }
+ // bitset to runcontainer (ported from Java RunContainer(
+ // BitmapContainer bc, int nbrRuns))
+ assert(n_runs > 0); // no empty bitmaps
+ run_container_t *answer = run_container_create_given_capacity(n_runs);
+
+ int long_ctr = 0;
+ uint64_t cur_word = c_qua_bitset->array[0];
+ int run_count = 0;
+ while (true) {
+ while (cur_word == UINT64_C(0) &&
+ long_ctr < BITSET_CONTAINER_SIZE_IN_WORDS - 1)
+ cur_word = c_qua_bitset->array[++long_ctr];
+
+ if (cur_word == UINT64_C(0)) {
+ bitset_container_free(c_qua_bitset);
+ *typecode_after = RUN_CONTAINER_TYPE_CODE;
+ return answer;
+ }
+
+ int local_run_start = __builtin_ctzll(cur_word);
+ int run_start = local_run_start + 64 * long_ctr;
+ uint64_t cur_word_with_1s = cur_word | (cur_word - 1);
+
+ int run_end = 0;
+ while (cur_word_with_1s == UINT64_C(0xFFFFFFFFFFFFFFFF) &&
+ long_ctr < BITSET_CONTAINER_SIZE_IN_WORDS - 1)
+ cur_word_with_1s = c_qua_bitset->array[++long_ctr];
+
+ if (cur_word_with_1s == UINT64_C(0xFFFFFFFFFFFFFFFF)) {
+ run_end = 64 + long_ctr * 64; // exclusive, I guess
+ add_run(answer, run_start, run_end - 1);
+ bitset_container_free(c_qua_bitset);
+ *typecode_after = RUN_CONTAINER_TYPE_CODE;
+ return answer;
+ }
+ int local_run_end = __builtin_ctzll(~cur_word_with_1s);
+ run_end = local_run_end + long_ctr * 64;
+ add_run(answer, run_start, run_end - 1);
+ run_count++;
+ cur_word = cur_word_with_1s & (cur_word_with_1s + 1);
+ }
+ return answer;
+ } else {
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+bitset_container_t *bitset_container_from_run_range(const run_container_t *run,
+ uint32_t min, uint32_t max) {
+ bitset_container_t *bitset = bitset_container_create();
+ int32_t union_cardinality = 0;
+ for (int32_t i = 0; i < run->n_runs; ++i) {
+ uint32_t rle_min = run->runs[i].value;
+ uint32_t rle_max = rle_min + run->runs[i].length;
+ bitset_set_lenrange(bitset->array, rle_min, rle_max - rle_min);
+ union_cardinality += run->runs[i].length + 1;
+ }
+ union_cardinality += max - min + 1;
+ union_cardinality -= bitset_lenrange_cardinality(bitset->array, min, max-min);
+ bitset_set_lenrange(bitset->array, min, max - min);
+ bitset->cardinality = union_cardinality;
+ return bitset;
+}
+/* end file src/containers/convert.c */
+/* begin file src/containers/mixed_andnot.c */
+/*
+ * mixed_andnot.c. More methods since operation is not symmetric,
+ * except no "wide" andnot , so no lazy options motivated.
+ */
+
+#include
+#include
+
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst, a valid array container that could be the same as dst.*/
+void array_bitset_container_andnot(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ array_container_t *dst) {
+ // follows Java implementation as of June 2016
+ if (dst->capacity < src_1->cardinality) {
+ array_container_grow(dst, src_1->cardinality, false);
+ }
+ int32_t newcard = 0;
+ const int32_t origcard = src_1->cardinality;
+ for (int i = 0; i < origcard; ++i) {
+ uint16_t key = src_1->array[i];
+ dst->array[newcard] = key;
+ newcard += 1 - bitset_container_contains(src_2, key);
+ }
+ dst->cardinality = newcard;
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * src_1 */
+
+void array_bitset_container_iandnot(array_container_t *src_1,
+ const bitset_container_t *src_2) {
+ array_bitset_container_andnot(src_1, src_2, src_1);
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst, which does not initially have a valid container.
+ * Return true for a bitset result; false for array
+ */
+
+bool bitset_array_container_andnot(const bitset_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ // Java did this directly, but we have option of asm or avx
+ bitset_container_t *result = bitset_container_create();
+ bitset_container_copy(src_1, result);
+ result->cardinality =
+ (int32_t)bitset_clear_list(result->array, (uint64_t)result->cardinality,
+ src_2->array, (uint64_t)src_2->cardinality);
+
+ // do required type conversions.
+ if (result->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(result);
+ bitset_container_free(result);
+ return false;
+ }
+ *dst = result;
+ return true;
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_array_container_iandnot(bitset_container_t *src_1,
+ const array_container_t *src_2,
+ void **dst) {
+ *dst = src_1;
+ src_1->cardinality =
+ (int32_t)bitset_clear_list(src_1->array, (uint64_t)src_1->cardinality,
+ src_2->array, (uint64_t)src_2->cardinality);
+
+ if (src_1->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(src_1);
+ bitset_container_free(src_1);
+ return false; // not bitset
+ } else
+ return true;
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_andnot(const run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ // follows the Java implementation as of June 2016
+ int card = run_container_cardinality(src_1);
+ if (card <= DEFAULT_MAX_SIZE) {
+ // must be an array
+ array_container_t *answer = array_container_create_given_capacity(card);
+ answer->cardinality = 0;
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ for (int run_value = rle.value; run_value <= rle.value + rle.length;
+ ++run_value) {
+ if (!bitset_container_get(src_2, (uint16_t)run_value)) {
+ answer->array[answer->cardinality++] = (uint16_t)run_value;
+ }
+ }
+ }
+ *dst = answer;
+ return false;
+ } else { // we guess it will be a bitset, though have to check guess when
+ // done
+ bitset_container_t *answer = bitset_container_clone(src_2);
+
+ uint32_t last_pos = 0;
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+
+ uint32_t start = rle.value;
+ uint32_t end = start + rle.length + 1;
+ bitset_reset_range(answer->array, last_pos, start);
+ bitset_flip_range(answer->array, start, end);
+ last_pos = end;
+ }
+ bitset_reset_range(answer->array, last_pos, (uint32_t)(1 << 16));
+
+ answer->cardinality = bitset_container_compute_cardinality(answer);
+
+ if (answer->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(answer);
+ bitset_container_free(answer);
+ return false; // not bitset
+ }
+ *dst = answer;
+ return true; // bitset
+ }
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_iandnot(run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ // dummy implementation
+ bool ans = run_bitset_container_andnot(src_1, src_2, dst);
+ run_container_free(src_1);
+ return ans;
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool bitset_run_container_andnot(const bitset_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ // follows Java implementation
+ bitset_container_t *result = bitset_container_create();
+
+ bitset_container_copy(src_1, result);
+ for (int32_t rlepos = 0; rlepos < src_2->n_runs; ++rlepos) {
+ rle16_t rle = src_2->runs[rlepos];
+ bitset_reset_range(result->array, rle.value,
+ rle.value + rle.length + UINT32_C(1));
+ }
+ result->cardinality = bitset_container_compute_cardinality(result);
+
+ if (result->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(result);
+ bitset_container_free(result);
+ return false; // not bitset
+ }
+ *dst = result;
+ return true; // bitset
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_run_container_iandnot(bitset_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ *dst = src_1;
+
+ for (int32_t rlepos = 0; rlepos < src_2->n_runs; ++rlepos) {
+ rle16_t rle = src_2->runs[rlepos];
+ bitset_reset_range(src_1->array, rle.value,
+ rle.value + rle.length + UINT32_C(1));
+ }
+ src_1->cardinality = bitset_container_compute_cardinality(src_1);
+
+ if (src_1->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(src_1);
+ bitset_container_free(src_1);
+ return false; // not bitset
+ } else
+ return true;
+}
+
+/* helper. a_out must be a valid array container with adequate capacity.
+ * Returns the cardinality of the output container. Partly Based on Java
+ * implementation Util.unsignedDifference.
+ *
+ * TODO: Util.unsignedDifference does not use advanceUntil. Is it cheaper
+ * to avoid advanceUntil?
+ */
+
+static int run_array_array_subtract(const run_container_t *r,
+ const array_container_t *a_in,
+ array_container_t *a_out) {
+ int out_card = 0;
+ int32_t in_array_pos =
+ -1; // since advanceUntil always assumes we start the search AFTER this
+
+ for (int rlepos = 0; rlepos < r->n_runs; rlepos++) {
+ int32_t start = r->runs[rlepos].value;
+ int32_t end = start + r->runs[rlepos].length + 1;
+
+ in_array_pos = advanceUntil(a_in->array, in_array_pos,
+ a_in->cardinality, (uint16_t)start);
+
+ if (in_array_pos >= a_in->cardinality) { // run has no items subtracted
+ for (int32_t i = start; i < end; ++i)
+ a_out->array[out_card++] = (uint16_t)i;
+ } else {
+ uint16_t next_nonincluded = a_in->array[in_array_pos];
+ if (next_nonincluded >= end) {
+ // another case when run goes unaltered
+ for (int32_t i = start; i < end; ++i)
+ a_out->array[out_card++] = (uint16_t)i;
+ in_array_pos--; // ensure we see this item again if necessary
+ } else {
+ for (int32_t i = start; i < end; ++i)
+ if (i != next_nonincluded)
+ a_out->array[out_card++] = (uint16_t)i;
+ else // 0 should ensure we don't match
+ next_nonincluded =
+ (in_array_pos + 1 >= a_in->cardinality)
+ ? 0
+ : a_in->array[++in_array_pos];
+ in_array_pos--; // see again
+ }
+ }
+ }
+ return out_card;
+}
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any type of container.
+ */
+
+int run_array_container_andnot(const run_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ // follows the Java impl as of June 2016
+
+ int card = run_container_cardinality(src_1);
+ const int arbitrary_threshold = 32;
+
+ if (card <= arbitrary_threshold) {
+ if (src_2->cardinality == 0) {
+ *dst = run_container_clone(src_1);
+ return RUN_CONTAINER_TYPE_CODE;
+ }
+ // Java's "lazyandNot.toEfficientContainer" thing
+ run_container_t *answer = run_container_create_given_capacity(
+ card + array_container_cardinality(src_2));
+
+ int rlepos = 0;
+ int xrlepos = 0; // "x" is src_2
+ rle16_t rle = src_1->runs[rlepos];
+ int32_t start = rle.value;
+ int32_t end = start + rle.length + 1;
+ int32_t xstart = src_2->array[xrlepos];
+
+ while ((rlepos < src_1->n_runs) && (xrlepos < src_2->cardinality)) {
+ if (end <= xstart) {
+ // output the first run
+ answer->runs[answer->n_runs++] =
+ (rle16_t){.value = (uint16_t)start,
+ .length = (uint16_t)(end - start - 1)};
+ rlepos++;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ } else if (xstart + 1 <= start) {
+ // exit the second run
+ xrlepos++;
+ if (xrlepos < src_2->cardinality) {
+ xstart = src_2->array[xrlepos];
+ }
+ } else {
+ if (start < xstart) {
+ answer->runs[answer->n_runs++] =
+ (rle16_t){.value = (uint16_t)start,
+ .length = (uint16_t)(xstart - start - 1)};
+ }
+ if (xstart + 1 < end) {
+ start = xstart + 1;
+ } else {
+ rlepos++;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ }
+ }
+ }
+ if (rlepos < src_1->n_runs) {
+ answer->runs[answer->n_runs++] =
+ (rle16_t){.value = (uint16_t)start,
+ .length = (uint16_t)(end - start - 1)};
+ rlepos++;
+ if (rlepos < src_1->n_runs) {
+ memcpy(answer->runs + answer->n_runs, src_1->runs + rlepos,
+ (src_1->n_runs - rlepos) * sizeof(rle16_t));
+ answer->n_runs += (src_1->n_runs - rlepos);
+ }
+ }
+ uint8_t return_type;
+ *dst = convert_run_to_efficient_container(answer, &return_type);
+ if (answer != *dst) run_container_free(answer);
+ return return_type;
+ }
+ // else it's a bitmap or array
+
+ if (card <= DEFAULT_MAX_SIZE) {
+ array_container_t *ac = array_container_create_given_capacity(card);
+ // nb Java code used a generic iterator-based merge to compute
+ // difference
+ ac->cardinality = run_array_array_subtract(src_1, src_2, ac);
+ *dst = ac;
+ return ARRAY_CONTAINER_TYPE_CODE;
+ }
+ bitset_container_t *ans = bitset_container_from_run(src_1);
+ bool result_is_bitset = bitset_array_container_iandnot(ans, src_2, dst);
+ return (result_is_bitset ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE);
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+int run_array_container_iandnot(run_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ // dummy implementation same as June 2016 Java
+ int ans = run_array_container_andnot(src_1, src_2, dst);
+ run_container_free(src_1);
+ return ans;
+}
+
+/* dst must be a valid array container, allowed to be src_1 */
+
+void array_run_container_andnot(const array_container_t *src_1,
+ const run_container_t *src_2,
+ array_container_t *dst) {
+ // basically following Java impl as of June 2016
+ if (src_1->cardinality > dst->capacity) {
+ array_container_grow(dst, src_1->cardinality, false);
+ }
+
+ if (src_2->n_runs == 0) {
+ memmove(dst->array, src_1->array,
+ sizeof(uint16_t) * src_1->cardinality);
+ dst->cardinality = src_1->cardinality;
+ return;
+ }
+ int32_t run_start = src_2->runs[0].value;
+ int32_t run_end = run_start + src_2->runs[0].length;
+ int which_run = 0;
+
+ uint16_t val = 0;
+ int dest_card = 0;
+ for (int i = 0; i < src_1->cardinality; ++i) {
+ val = src_1->array[i];
+ if (val < run_start)
+ dst->array[dest_card++] = val;
+ else if (val <= run_end) {
+ ; // omitted item
+ } else {
+ do {
+ if (which_run + 1 < src_2->n_runs) {
+ ++which_run;
+ run_start = src_2->runs[which_run].value;
+ run_end = run_start + src_2->runs[which_run].length;
+
+ } else
+ run_start = run_end = (1 << 16) + 1;
+ } while (val > run_end);
+ --i;
+ }
+ }
+ dst->cardinality = dest_card;
+}
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+void array_run_container_iandnot(array_container_t *src_1,
+ const run_container_t *src_2) {
+ array_run_container_andnot(src_1, src_2, src_1);
+}
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int run_run_container_andnot(const run_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ run_container_t *ans = run_container_create();
+ run_container_andnot(src_1, src_2, ans);
+ uint8_t typecode_after;
+ *dst = convert_run_to_efficient_container_and_free(ans, &typecode_after);
+ return typecode_after;
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+int run_run_container_iandnot(run_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ // following Java impl as of June 2016 (dummy)
+ int ans = run_run_container_andnot(src_1, src_2, dst);
+ run_container_free(src_1);
+ return ans;
+}
+
+/*
+ * dst is a valid array container and may be the same as src_1
+ */
+
+void array_array_container_andnot(const array_container_t *src_1,
+ const array_container_t *src_2,
+ array_container_t *dst) {
+ array_container_andnot(src_1, src_2, dst);
+}
+
+/* inplace array-array andnot will always be able to reuse the space of
+ * src_1 */
+void array_array_container_iandnot(array_container_t *src_1,
+ const array_container_t *src_2) {
+ array_container_andnot(src_1, src_2, src_1);
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). Return value is
+ * "dst is a bitset"
+ */
+
+bool bitset_bitset_container_andnot(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst) {
+ bitset_container_t *ans = bitset_container_create();
+ int card = bitset_container_andnot(src_1, src_2, ans);
+ if (card <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(ans);
+ bitset_container_free(ans);
+ return false; // not bitset
+ } else {
+ *dst = ans;
+ return true;
+ }
+}
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_bitset_container_iandnot(bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst) {
+ int card = bitset_container_andnot(src_1, src_2, src_1);
+ if (card <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(src_1);
+ bitset_container_free(src_1);
+ return false; // not bitset
+ } else {
+ *dst = src_1;
+ return true;
+ }
+}
+/* end file src/containers/mixed_andnot.c */
+/* begin file src/containers/mixed_equal.c */
+
+bool array_container_equal_bitset(const array_container_t* container1,
+ const bitset_container_t* container2) {
+ if (container2->cardinality != BITSET_UNKNOWN_CARDINALITY) {
+ if (container2->cardinality != container1->cardinality) {
+ return false;
+ }
+ }
+ int32_t pos = 0;
+ for (int32_t i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; ++i) {
+ uint64_t w = container2->array[i];
+ while (w != 0) {
+ uint64_t t = w & (~w + 1);
+ uint16_t r = i * 64 + __builtin_ctzll(w);
+ if (pos >= container1->cardinality) {
+ return false;
+ }
+ if (container1->array[pos] != r) {
+ return false;
+ }
+ ++pos;
+ w ^= t;
+ }
+ }
+ return (pos == container1->cardinality);
+}
+
+bool run_container_equals_array(const run_container_t* container1,
+ const array_container_t* container2) {
+ if (run_container_cardinality(container1) != container2->cardinality)
+ return false;
+ int32_t pos = 0;
+ for (int i = 0; i < container1->n_runs; ++i) {
+ const uint32_t run_start = container1->runs[i].value;
+ const uint32_t le = container1->runs[i].length;
+
+ if (container2->array[pos] != run_start) {
+ return false;
+ }
+
+ if (container2->array[pos + le] != run_start + le) {
+ return false;
+ }
+
+ pos += le + 1;
+ }
+ return true;
+}
+
+bool run_container_equals_bitset(const run_container_t* container1,
+ const bitset_container_t* container2) {
+
+ int run_card = run_container_cardinality(container1);
+ int bitset_card = (container2->cardinality != BITSET_UNKNOWN_CARDINALITY) ?
+ container2->cardinality :
+ bitset_container_compute_cardinality(container2);
+ if (bitset_card != run_card) {
+ return false;
+ }
+
+ for (int32_t i = 0; i < container1->n_runs; i++) {
+ uint32_t begin = container1->runs[i].value;
+ if (container1->runs[i].length) {
+ uint32_t end = begin + container1->runs[i].length + 1;
+ if (!bitset_container_contains_range(container2, begin, end)) {
+ return false;
+ }
+ } else {
+ if (!bitset_container_contains(container2, begin)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+/* end file src/containers/mixed_equal.c */
+/* begin file src/containers/mixed_intersection.c */
+/*
+ * mixed_intersection.c
+ *
+ */
+
+
+/* Compute the intersection of src_1 and src_2 and write the result to
+ * dst. */
+void array_bitset_container_intersection(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ array_container_t *dst) {
+ if (dst->capacity < src_1->cardinality) {
+ array_container_grow(dst, src_1->cardinality, false);
+ }
+ int32_t newcard = 0; // dst could be src_1
+ const int32_t origcard = src_1->cardinality;
+ for (int i = 0; i < origcard; ++i) {
+ uint16_t key = src_1->array[i];
+ // this branchless approach is much faster...
+ dst->array[newcard] = key;
+ newcard += bitset_container_contains(src_2, key);
+ /**
+ * we could do it this way instead...
+ * if (bitset_container_contains(src_2, key)) {
+ * dst->array[newcard++] = key;
+ * }
+ * but if the result is unpredictable, the processor generates
+ * many mispredicted branches.
+ * Difference can be huge (from 3 cycles when predictable all the way
+ * to 16 cycles when unpredictable.
+ * See
+ * https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/extra/bitset/c/arraybitsetintersection.c
+ */
+ }
+ dst->cardinality = newcard;
+}
+
+/* Compute the size of the intersection of src_1 and src_2. */
+int array_bitset_container_intersection_cardinality(
+ const array_container_t *src_1, const bitset_container_t *src_2) {
+ int32_t newcard = 0;
+ const int32_t origcard = src_1->cardinality;
+ for (int i = 0; i < origcard; ++i) {
+ uint16_t key = src_1->array[i];
+ newcard += bitset_container_contains(src_2, key);
+ }
+ return newcard;
+}
+
+
+bool array_bitset_container_intersect(const array_container_t *src_1,
+ const bitset_container_t *src_2) {
+ const int32_t origcard = src_1->cardinality;
+ for (int i = 0; i < origcard; ++i) {
+ uint16_t key = src_1->array[i];
+ if(bitset_container_contains(src_2, key)) return true;
+ }
+ return false;
+}
+
+/* Compute the intersection of src_1 and src_2 and write the result to
+ * dst. It is allowed for dst to be equal to src_1. We assume that dst is a
+ * valid container. */
+void array_run_container_intersection(const array_container_t *src_1,
+ const run_container_t *src_2,
+ array_container_t *dst) {
+ if (run_container_is_full(src_2)) {
+ if (dst != src_1) array_container_copy(src_1, dst);
+ return;
+ }
+ if (dst->capacity < src_1->cardinality) {
+ array_container_grow(dst, src_1->cardinality, false);
+ }
+ if (src_2->n_runs == 0) {
+ return;
+ }
+ int32_t rlepos = 0;
+ int32_t arraypos = 0;
+ rle16_t rle = src_2->runs[rlepos];
+ int32_t newcard = 0;
+ while (arraypos < src_1->cardinality) {
+ const uint16_t arrayval = src_1->array[arraypos];
+ while (rle.value + rle.length <
+ arrayval) { // this will frequently be false
+ ++rlepos;
+ if (rlepos == src_2->n_runs) {
+ dst->cardinality = newcard;
+ return; // we are done
+ }
+ rle = src_2->runs[rlepos];
+ }
+ if (rle.value > arrayval) {
+ arraypos = advanceUntil(src_1->array, arraypos, src_1->cardinality,
+ rle.value);
+ } else {
+ dst->array[newcard] = arrayval;
+ newcard++;
+ arraypos++;
+ }
+ }
+ dst->cardinality = newcard;
+}
+
+/* Compute the intersection of src_1 and src_2 and write the result to
+ * *dst. If the result is true then the result is a bitset_container_t
+ * otherwise is a array_container_t. If *dst == src_2, an in-place processing
+ * is attempted.*/
+bool run_bitset_container_intersection(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst) {
+ if (run_container_is_full(src_1)) {
+ if (*dst != src_2) *dst = bitset_container_clone(src_2);
+ return true;
+ }
+ int32_t card = run_container_cardinality(src_1);
+ if (card <= DEFAULT_MAX_SIZE) {
+ // result can only be an array (assuming that we never make a
+ // RunContainer)
+ if (card > src_2->cardinality) {
+ card = src_2->cardinality;
+ }
+ array_container_t *answer = array_container_create_given_capacity(card);
+ *dst = answer;
+ if (*dst == NULL) {
+ return false;
+ }
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ uint32_t endofrun = (uint32_t)rle.value + rle.length;
+ for (uint32_t runValue = rle.value; runValue <= endofrun;
+ ++runValue) {
+ answer->array[answer->cardinality] = (uint16_t)runValue;
+ answer->cardinality +=
+ bitset_container_contains(src_2, runValue);
+ }
+ }
+ return false;
+ }
+ if (*dst == src_2) { // we attempt in-place
+ bitset_container_t *answer = (bitset_container_t *)*dst;
+ uint32_t start = 0;
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ const rle16_t rle = src_1->runs[rlepos];
+ uint32_t end = rle.value;
+ bitset_reset_range(src_2->array, start, end);
+
+ start = end + rle.length + 1;
+ }
+ bitset_reset_range(src_2->array, start, UINT32_C(1) << 16);
+ answer->cardinality = bitset_container_compute_cardinality(answer);
+ if (src_2->cardinality > DEFAULT_MAX_SIZE) {
+ return true;
+ } else {
+ array_container_t *newanswer = array_container_from_bitset(src_2);
+ if (newanswer == NULL) {
+ *dst = NULL;
+ return false;
+ }
+ *dst = newanswer;
+ return false;
+ }
+ } else { // no inplace
+ // we expect the answer to be a bitmap (if we are lucky)
+ bitset_container_t *answer = bitset_container_clone(src_2);
+
+ *dst = answer;
+ if (answer == NULL) {
+ return true;
+ }
+ uint32_t start = 0;
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ const rle16_t rle = src_1->runs[rlepos];
+ uint32_t end = rle.value;
+ bitset_reset_range(answer->array, start, end);
+ start = end + rle.length + 1;
+ }
+ bitset_reset_range(answer->array, start, UINT32_C(1) << 16);
+ answer->cardinality = bitset_container_compute_cardinality(answer);
+
+ if (answer->cardinality > DEFAULT_MAX_SIZE) {
+ return true;
+ } else {
+ array_container_t *newanswer = array_container_from_bitset(answer);
+ bitset_container_free((bitset_container_t *)*dst);
+ if (newanswer == NULL) {
+ *dst = NULL;
+ return false;
+ }
+ *dst = newanswer;
+ return false;
+ }
+ }
+}
+
+/* Compute the size of the intersection between src_1 and src_2 . */
+int array_run_container_intersection_cardinality(const array_container_t *src_1,
+ const run_container_t *src_2) {
+ if (run_container_is_full(src_2)) {
+ return src_1->cardinality;
+ }
+ if (src_2->n_runs == 0) {
+ return 0;
+ }
+ int32_t rlepos = 0;
+ int32_t arraypos = 0;
+ rle16_t rle = src_2->runs[rlepos];
+ int32_t newcard = 0;
+ while (arraypos < src_1->cardinality) {
+ const uint16_t arrayval = src_1->array[arraypos];
+ while (rle.value + rle.length <
+ arrayval) { // this will frequently be false
+ ++rlepos;
+ if (rlepos == src_2->n_runs) {
+ return newcard; // we are done
+ }
+ rle = src_2->runs[rlepos];
+ }
+ if (rle.value > arrayval) {
+ arraypos = advanceUntil(src_1->array, arraypos, src_1->cardinality,
+ rle.value);
+ } else {
+ newcard++;
+ arraypos++;
+ }
+ }
+ return newcard;
+}
+
+/* Compute the intersection between src_1 and src_2
+ **/
+int run_bitset_container_intersection_cardinality(
+ const run_container_t *src_1, const bitset_container_t *src_2) {
+ if (run_container_is_full(src_1)) {
+ return bitset_container_cardinality(src_2);
+ }
+ int answer = 0;
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ answer +=
+ bitset_lenrange_cardinality(src_2->array, rle.value, rle.length);
+ }
+ return answer;
+}
+
+
+bool array_run_container_intersect(const array_container_t *src_1,
+ const run_container_t *src_2) {
+ if( run_container_is_full(src_2) ) {
+ return !array_container_empty(src_1);
+ }
+ if (src_2->n_runs == 0) {
+ return false;
+ }
+ int32_t rlepos = 0;
+ int32_t arraypos = 0;
+ rle16_t rle = src_2->runs[rlepos];
+ while (arraypos < src_1->cardinality) {
+ const uint16_t arrayval = src_1->array[arraypos];
+ while (rle.value + rle.length <
+ arrayval) { // this will frequently be false
+ ++rlepos;
+ if (rlepos == src_2->n_runs) {
+ return false; // we are done
+ }
+ rle = src_2->runs[rlepos];
+ }
+ if (rle.value > arrayval) {
+ arraypos = advanceUntil(src_1->array, arraypos, src_1->cardinality,
+ rle.value);
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Compute the intersection between src_1 and src_2
+ **/
+bool run_bitset_container_intersect(const run_container_t *src_1,
+ const bitset_container_t *src_2) {
+ if( run_container_is_full(src_1) ) {
+ return !bitset_container_empty(src_2);
+ }
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ if(!bitset_lenrange_empty(src_2->array, rle.value,rle.length)) return true;
+ }
+ return false;
+}
+
+/*
+ * Compute the intersection between src_1 and src_2 and write the result
+ * to *dst. If the return function is true, the result is a bitset_container_t
+ * otherwise is a array_container_t.
+ */
+bool bitset_bitset_container_intersection(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst) {
+ const int newCardinality = bitset_container_and_justcard(src_1, src_2);
+ if (newCardinality > DEFAULT_MAX_SIZE) {
+ *dst = bitset_container_create();
+ if (*dst != NULL) {
+ bitset_container_and_nocard(src_1, src_2,
+ (bitset_container_t *)*dst);
+ ((bitset_container_t *)*dst)->cardinality = newCardinality;
+ }
+ return true; // it is a bitset
+ }
+ *dst = array_container_create_given_capacity(newCardinality);
+ if (*dst != NULL) {
+ ((array_container_t *)*dst)->cardinality = newCardinality;
+ bitset_extract_intersection_setbits_uint16(
+ ((const bitset_container_t *)src_1)->array,
+ ((const bitset_container_t *)src_2)->array,
+ BITSET_CONTAINER_SIZE_IN_WORDS, ((array_container_t *)*dst)->array,
+ 0);
+ }
+ return false; // not a bitset
+}
+
+bool bitset_bitset_container_intersection_inplace(
+ bitset_container_t *src_1, const bitset_container_t *src_2, void **dst) {
+ const int newCardinality = bitset_container_and_justcard(src_1, src_2);
+ if (newCardinality > DEFAULT_MAX_SIZE) {
+ *dst = src_1;
+ bitset_container_and_nocard(src_1, src_2, src_1);
+ ((bitset_container_t *)*dst)->cardinality = newCardinality;
+ return true; // it is a bitset
+ }
+ *dst = array_container_create_given_capacity(newCardinality);
+ if (*dst != NULL) {
+ ((array_container_t *)*dst)->cardinality = newCardinality;
+ bitset_extract_intersection_setbits_uint16(
+ ((const bitset_container_t *)src_1)->array,
+ ((const bitset_container_t *)src_2)->array,
+ BITSET_CONTAINER_SIZE_IN_WORDS, ((array_container_t *)*dst)->array,
+ 0);
+ }
+ return false; // not a bitset
+}
+/* end file src/containers/mixed_intersection.c */
+/* begin file src/containers/mixed_negation.c */
+/*
+ * mixed_negation.c
+ *
+ */
+
+#include
+#include
+
+
+// TODO: make simplified and optimized negation code across
+// the full range.
+
+/* Negation across the entire range of the container.
+ * Compute the negation of src and write the result
+ * to *dst. The complement of a
+ * sufficiently sparse set will always be dense and a hence a bitmap
+' * We assume that dst is pre-allocated and a valid bitset container
+ * There can be no in-place version.
+ */
+void array_container_negation(const array_container_t *src,
+ bitset_container_t *dst) {
+ uint64_t card = UINT64_C(1 << 16);
+ bitset_container_set_all(dst);
+
+ dst->cardinality = (int32_t)bitset_clear_list(dst->array, card, src->array,
+ (uint64_t)src->cardinality);
+}
+
+/* Negation across the entire range of the container
+ * Compute the negation of src and write the result
+ * to *dst. A true return value indicates a bitset result,
+ * otherwise the result is an array container.
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+bool bitset_container_negation(const bitset_container_t *src, void **dst) {
+ return bitset_container_negation_range(src, 0, (1 << 16), dst);
+}
+
+/* inplace version */
+/*
+ * Same as bitset_container_negation except that if the output is to
+ * be a
+ * bitset_container_t, then src is modified and no allocation is made.
+ * If the output is to be an array_container_t, then caller is responsible
+ * to free the container.
+ * In all cases, the result is in *dst.
+ */
+bool bitset_container_negation_inplace(bitset_container_t *src, void **dst) {
+ return bitset_container_negation_range_inplace(src, 0, (1 << 16), dst);
+}
+
+/* Negation across the entire range of container
+ * Compute the negation of src and write the result
+ * to *dst. Return values are the *_TYPECODES as defined * in containers.h
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+int run_container_negation(const run_container_t *src, void **dst) {
+ return run_container_negation_range(src, 0, (1 << 16), dst);
+}
+
+/*
+ * Same as run_container_negation except that if the output is to
+ * be a
+ * run_container_t, and has the capacity to hold the result,
+ * then src is modified and no allocation is made.
+ * In all cases, the result is in *dst.
+ */
+int run_container_negation_inplace(run_container_t *src, void **dst) {
+ return run_container_negation_range_inplace(src, 0, (1 << 16), dst);
+}
+
+/* Negation across a range of the container.
+ * Compute the negation of src and write the result
+ * to *dst. Returns true if the result is a bitset container
+ * and false for an array container. *dst is not preallocated.
+ */
+bool array_container_negation_range(const array_container_t *src,
+ const int range_start, const int range_end,
+ void **dst) {
+ /* close port of the Java implementation */
+ if (range_start >= range_end) {
+ *dst = array_container_clone(src);
+ return false;
+ }
+
+ int32_t start_index =
+ binarySearch(src->array, src->cardinality, (uint16_t)range_start);
+ if (start_index < 0) start_index = -start_index - 1;
+
+ int32_t last_index =
+ binarySearch(src->array, src->cardinality, (uint16_t)(range_end - 1));
+ if (last_index < 0) last_index = -last_index - 2;
+
+ const int32_t current_values_in_range = last_index - start_index + 1;
+ const int32_t span_to_be_flipped = range_end - range_start;
+ const int32_t new_values_in_range =
+ span_to_be_flipped - current_values_in_range;
+ const int32_t cardinality_change =
+ new_values_in_range - current_values_in_range;
+ const int32_t new_cardinality = src->cardinality + cardinality_change;
+
+ if (new_cardinality > DEFAULT_MAX_SIZE) {
+ bitset_container_t *temp = bitset_container_from_array(src);
+ bitset_flip_range(temp->array, (uint32_t)range_start,
+ (uint32_t)range_end);
+ temp->cardinality = new_cardinality;
+ *dst = temp;
+ return true;
+ }
+
+ array_container_t *arr =
+ array_container_create_given_capacity(new_cardinality);
+ *dst = (void *)arr;
+ if(new_cardinality == 0) {
+ arr->cardinality = new_cardinality;
+ return false; // we are done.
+ }
+ // copy stuff before the active area
+ memcpy(arr->array, src->array, start_index * sizeof(uint16_t));
+
+ // work on the range
+ int32_t out_pos = start_index, in_pos = start_index;
+ int32_t val_in_range = range_start;
+ for (; val_in_range < range_end && in_pos <= last_index; ++val_in_range) {
+ if ((uint16_t)val_in_range != src->array[in_pos]) {
+ arr->array[out_pos++] = (uint16_t)val_in_range;
+ } else {
+ ++in_pos;
+ }
+ }
+ for (; val_in_range < range_end; ++val_in_range)
+ arr->array[out_pos++] = (uint16_t)val_in_range;
+
+ // content after the active range
+ memcpy(arr->array + out_pos, src->array + (last_index + 1),
+ (src->cardinality - (last_index + 1)) * sizeof(uint16_t));
+ arr->cardinality = new_cardinality;
+ return false;
+}
+
+/* Even when the result would fit, it is unclear how to make an
+ * inplace version without inefficient copying.
+ */
+
+bool array_container_negation_range_inplace(array_container_t *src,
+ const int range_start,
+ const int range_end, void **dst) {
+ bool ans = array_container_negation_range(src, range_start, range_end, dst);
+ // TODO : try a real inplace version
+ array_container_free(src);
+ return ans;
+}
+
+/* Negation across a range of the container
+ * Compute the negation of src and write the result
+ * to *dst. A true return value indicates a bitset result,
+ * otherwise the result is an array container.
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+bool bitset_container_negation_range(const bitset_container_t *src,
+ const int range_start, const int range_end,
+ void **dst) {
+ // TODO maybe consider density-based estimate
+ // and sometimes build result directly as array, with
+ // conversion back to bitset if wrong. Or determine
+ // actual result cardinality, then go directly for the known final cont.
+
+ // keep computation using bitsets as long as possible.
+ bitset_container_t *t = bitset_container_clone(src);
+ bitset_flip_range(t->array, (uint32_t)range_start, (uint32_t)range_end);
+ t->cardinality = bitset_container_compute_cardinality(t);
+
+ if (t->cardinality > DEFAULT_MAX_SIZE) {
+ *dst = t;
+ return true;
+ } else {
+ *dst = array_container_from_bitset(t);
+ bitset_container_free(t);
+ return false;
+ }
+}
+
+/* inplace version */
+/*
+ * Same as bitset_container_negation except that if the output is to
+ * be a
+ * bitset_container_t, then src is modified and no allocation is made.
+ * If the output is to be an array_container_t, then caller is responsible
+ * to free the container.
+ * In all cases, the result is in *dst.
+ */
+bool bitset_container_negation_range_inplace(bitset_container_t *src,
+ const int range_start,
+ const int range_end, void **dst) {
+ bitset_flip_range(src->array, (uint32_t)range_start, (uint32_t)range_end);
+ src->cardinality = bitset_container_compute_cardinality(src);
+ if (src->cardinality > DEFAULT_MAX_SIZE) {
+ *dst = src;
+ return true;
+ }
+ *dst = array_container_from_bitset(src);
+ bitset_container_free(src);
+ return false;
+}
+
+/* Negation across a range of container
+ * Compute the negation of src and write the result
+ * to *dst. Return values are the *_TYPECODES as defined * in containers.h
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+int run_container_negation_range(const run_container_t *src,
+ const int range_start, const int range_end,
+ void **dst) {
+ uint8_t return_typecode;
+
+ // follows the Java implementation
+ if (range_end <= range_start) {
+ *dst = run_container_clone(src);
+ return RUN_CONTAINER_TYPE_CODE;
+ }
+
+ run_container_t *ans = run_container_create_given_capacity(
+ src->n_runs + 1); // src->n_runs + 1);
+ int k = 0;
+ for (; k < src->n_runs && src->runs[k].value < range_start; ++k) {
+ ans->runs[k] = src->runs[k];
+ ans->n_runs++;
+ }
+
+ run_container_smart_append_exclusive(
+ ans, (uint16_t)range_start, (uint16_t)(range_end - range_start - 1));
+
+ for (; k < src->n_runs; ++k) {
+ run_container_smart_append_exclusive(ans, src->runs[k].value,
+ src->runs[k].length);
+ }
+
+ *dst = convert_run_to_efficient_container(ans, &return_typecode);
+ if (return_typecode != RUN_CONTAINER_TYPE_CODE) run_container_free(ans);
+
+ return return_typecode;
+}
+
+/*
+ * Same as run_container_negation except that if the output is to
+ * be a
+ * run_container_t, and has the capacity to hold the result,
+ * then src is modified and no allocation is made.
+ * In all cases, the result is in *dst.
+ */
+int run_container_negation_range_inplace(run_container_t *src,
+ const int range_start,
+ const int range_end, void **dst) {
+ uint8_t return_typecode;
+
+ if (range_end <= range_start) {
+ *dst = src;
+ return RUN_CONTAINER_TYPE_CODE;
+ }
+
+ // TODO: efficient special case when range is 0 to 65535 inclusive
+
+ if (src->capacity == src->n_runs) {
+ // no excess room. More checking to see if result can fit
+ bool last_val_before_range = false;
+ bool first_val_in_range = false;
+ bool last_val_in_range = false;
+ bool first_val_past_range = false;
+
+ if (range_start > 0)
+ last_val_before_range =
+ run_container_contains(src, (uint16_t)(range_start - 1));
+ first_val_in_range = run_container_contains(src, (uint16_t)range_start);
+
+ if (last_val_before_range == first_val_in_range) {
+ last_val_in_range =
+ run_container_contains(src, (uint16_t)(range_end - 1));
+ if (range_end != 0x10000)
+ first_val_past_range =
+ run_container_contains(src, (uint16_t)range_end);
+
+ if (last_val_in_range ==
+ first_val_past_range) { // no space for inplace
+ int ans = run_container_negation_range(src, range_start,
+ range_end, dst);
+ run_container_free(src);
+ return ans;
+ }
+ }
+ }
+ // all other cases: result will fit
+
+ run_container_t *ans = src;
+ int my_nbr_runs = src->n_runs;
+
+ ans->n_runs = 0;
+ int k = 0;
+ for (; (k < my_nbr_runs) && (src->runs[k].value < range_start); ++k) {
+ // ans->runs[k] = src->runs[k]; (would be self-copy)
+ ans->n_runs++;
+ }
+
+ // as with Java implementation, use locals to give self a buffer of depth 1
+ rle16_t buffered = (rle16_t){.value = (uint16_t)0, .length = (uint16_t)0};
+ rle16_t next = buffered;
+ if (k < my_nbr_runs) buffered = src->runs[k];
+
+ run_container_smart_append_exclusive(
+ ans, (uint16_t)range_start, (uint16_t)(range_end - range_start - 1));
+
+ for (; k < my_nbr_runs; ++k) {
+ if (k + 1 < my_nbr_runs) next = src->runs[k + 1];
+
+ run_container_smart_append_exclusive(ans, buffered.value,
+ buffered.length);
+ buffered = next;
+ }
+
+ *dst = convert_run_to_efficient_container(ans, &return_typecode);
+ if (return_typecode != RUN_CONTAINER_TYPE_CODE) run_container_free(ans);
+
+ return return_typecode;
+}
+/* end file src/containers/mixed_negation.c */
+/* begin file src/containers/mixed_subset.c */
+
+bool array_container_is_subset_bitset(const array_container_t* container1,
+ const bitset_container_t* container2) {
+ if (container2->cardinality != BITSET_UNKNOWN_CARDINALITY) {
+ if (container2->cardinality < container1->cardinality) {
+ return false;
+ }
+ }
+ for (int i = 0; i < container1->cardinality; ++i) {
+ if (!bitset_container_contains(container2, container1->array[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool run_container_is_subset_array(const run_container_t* container1,
+ const array_container_t* container2) {
+ if (run_container_cardinality(container1) > container2->cardinality)
+ return false;
+ int32_t start_pos = -1, stop_pos = -1;
+ for (int i = 0; i < container1->n_runs; ++i) {
+ int32_t start = container1->runs[i].value;
+ int32_t stop = start + container1->runs[i].length;
+ start_pos = advanceUntil(container2->array, stop_pos,
+ container2->cardinality, start);
+ stop_pos = advanceUntil(container2->array, stop_pos,
+ container2->cardinality, stop);
+ if (start_pos == container2->cardinality) {
+ return false;
+ } else if (stop_pos - start_pos != stop - start ||
+ container2->array[start_pos] != start ||
+ container2->array[stop_pos] != stop) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool array_container_is_subset_run(const array_container_t* container1,
+ const run_container_t* container2) {
+ if (container1->cardinality > run_container_cardinality(container2))
+ return false;
+ int i_array = 0, i_run = 0;
+ while (i_array < container1->cardinality && i_run < container2->n_runs) {
+ uint32_t start = container2->runs[i_run].value;
+ uint32_t stop = start + container2->runs[i_run].length;
+ if (container1->array[i_array] < start) {
+ return false;
+ } else if (container1->array[i_array] > stop) {
+ i_run++;
+ } else { // the value of the array is in the run
+ i_array++;
+ }
+ }
+ if (i_array == container1->cardinality) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool run_container_is_subset_bitset(const run_container_t* container1,
+ const bitset_container_t* container2) {
+ // todo: this code could be much faster
+ if (container2->cardinality != BITSET_UNKNOWN_CARDINALITY) {
+ if (container2->cardinality < run_container_cardinality(container1)) {
+ return false;
+ }
+ } else {
+ int32_t card = bitset_container_compute_cardinality(
+ container2); // modify container2?
+ if (card < run_container_cardinality(container1)) {
+ return false;
+ }
+ }
+ for (int i = 0; i < container1->n_runs; ++i) {
+ uint32_t run_start = container1->runs[i].value;
+ uint32_t le = container1->runs[i].length;
+ for (uint32_t j = run_start; j <= run_start + le; ++j) {
+ if (!bitset_container_contains(container2, j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool bitset_container_is_subset_run(const bitset_container_t* container1,
+ const run_container_t* container2) {
+ // todo: this code could be much faster
+ if (container1->cardinality != BITSET_UNKNOWN_CARDINALITY) {
+ if (container1->cardinality > run_container_cardinality(container2)) {
+ return false;
+ }
+ }
+ int32_t i_bitset = 0, i_run = 0;
+ while (i_bitset < BITSET_CONTAINER_SIZE_IN_WORDS &&
+ i_run < container2->n_runs) {
+ uint64_t w = container1->array[i_bitset];
+ while (w != 0 && i_run < container2->n_runs) {
+ uint32_t start = container2->runs[i_run].value;
+ uint32_t stop = start + container2->runs[i_run].length;
+ uint64_t t = w & (~w + 1);
+ uint16_t r = i_bitset * 64 + __builtin_ctzll(w);
+ if (r < start) {
+ return false;
+ } else if (r > stop) {
+ i_run++;
+ continue;
+ } else {
+ w ^= t;
+ }
+ }
+ if (w == 0) {
+ i_bitset++;
+ } else {
+ return false;
+ }
+ }
+ if (i_bitset < BITSET_CONTAINER_SIZE_IN_WORDS) {
+ // terminated iterating on the run containers, check that rest of bitset
+ // is empty
+ for (; i_bitset < BITSET_CONTAINER_SIZE_IN_WORDS; i_bitset++) {
+ if (container1->array[i_bitset] != 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+/* end file src/containers/mixed_subset.c */
+/* begin file src/containers/mixed_union.c */
+/*
+ * mixed_union.c
+ *
+ */
+
+#include
+#include
+
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. */
+void array_bitset_container_union(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst) {
+ if (src_2 != dst) bitset_container_copy(src_2, dst);
+ dst->cardinality = (int32_t)bitset_set_list_withcard(
+ dst->array, dst->cardinality, src_1->array, src_1->cardinality);
+}
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. It is allowed for src_2 to be dst. This version does not
+ * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY). */
+void array_bitset_container_lazy_union(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst) {
+ if (src_2 != dst) bitset_container_copy(src_2, dst);
+ bitset_set_list(dst->array, src_1->array, src_1->cardinality);
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY;
+}
+
+void run_bitset_container_union(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst) {
+ assert(!run_container_is_full(src_1)); // catch this case upstream
+ if (src_2 != dst) bitset_container_copy(src_2, dst);
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ bitset_set_lenrange(dst->array, rle.value, rle.length);
+ }
+ dst->cardinality = bitset_container_compute_cardinality(dst);
+}
+
+void run_bitset_container_lazy_union(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst) {
+ assert(!run_container_is_full(src_1)); // catch this case upstream
+ if (src_2 != dst) bitset_container_copy(src_2, dst);
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ bitset_set_lenrange(dst->array, rle.value, rle.length);
+ }
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY;
+}
+
+// why do we leave the result as a run container??
+void array_run_container_union(const array_container_t *src_1,
+ const run_container_t *src_2,
+ run_container_t *dst) {
+ if (run_container_is_full(src_2)) {
+ run_container_copy(src_2, dst);
+ return;
+ }
+ // TODO: see whether the "2*" is spurious
+ run_container_grow(dst, 2 * (src_1->cardinality + src_2->n_runs), false);
+ int32_t rlepos = 0;
+ int32_t arraypos = 0;
+ rle16_t previousrle;
+ if (src_2->runs[rlepos].value <= src_1->array[arraypos]) {
+ previousrle = run_container_append_first(dst, src_2->runs[rlepos]);
+ rlepos++;
+ } else {
+ previousrle =
+ run_container_append_value_first(dst, src_1->array[arraypos]);
+ arraypos++;
+ }
+ while ((rlepos < src_2->n_runs) && (arraypos < src_1->cardinality)) {
+ if (src_2->runs[rlepos].value <= src_1->array[arraypos]) {
+ run_container_append(dst, src_2->runs[rlepos], &previousrle);
+ rlepos++;
+ } else {
+ run_container_append_value(dst, src_1->array[arraypos],
+ &previousrle);
+ arraypos++;
+ }
+ }
+ if (arraypos < src_1->cardinality) {
+ while (arraypos < src_1->cardinality) {
+ run_container_append_value(dst, src_1->array[arraypos],
+ &previousrle);
+ arraypos++;
+ }
+ } else {
+ while (rlepos < src_2->n_runs) {
+ run_container_append(dst, src_2->runs[rlepos], &previousrle);
+ rlepos++;
+ }
+ }
+}
+
+void array_run_container_inplace_union(const array_container_t *src_1,
+ run_container_t *src_2) {
+ if (run_container_is_full(src_2)) {
+ return;
+ }
+ const int32_t maxoutput = src_1->cardinality + src_2->n_runs;
+ const int32_t neededcapacity = maxoutput + src_2->n_runs;
+ if (src_2->capacity < neededcapacity)
+ run_container_grow(src_2, neededcapacity, true);
+ memmove(src_2->runs + maxoutput, src_2->runs,
+ src_2->n_runs * sizeof(rle16_t));
+ rle16_t *inputsrc2 = src_2->runs + maxoutput;
+ int32_t rlepos = 0;
+ int32_t arraypos = 0;
+ int src2nruns = src_2->n_runs;
+ src_2->n_runs = 0;
+
+ rle16_t previousrle;
+
+ if (inputsrc2[rlepos].value <= src_1->array[arraypos]) {
+ previousrle = run_container_append_first(src_2, inputsrc2[rlepos]);
+ rlepos++;
+ } else {
+ previousrle =
+ run_container_append_value_first(src_2, src_1->array[arraypos]);
+ arraypos++;
+ }
+
+ while ((rlepos < src2nruns) && (arraypos < src_1->cardinality)) {
+ if (inputsrc2[rlepos].value <= src_1->array[arraypos]) {
+ run_container_append(src_2, inputsrc2[rlepos], &previousrle);
+ rlepos++;
+ } else {
+ run_container_append_value(src_2, src_1->array[arraypos],
+ &previousrle);
+ arraypos++;
+ }
+ }
+ if (arraypos < src_1->cardinality) {
+ while (arraypos < src_1->cardinality) {
+ run_container_append_value(src_2, src_1->array[arraypos],
+ &previousrle);
+ arraypos++;
+ }
+ } else {
+ while (rlepos < src2nruns) {
+ run_container_append(src_2, inputsrc2[rlepos], &previousrle);
+ rlepos++;
+ }
+ }
+}
+
+bool array_array_container_union(const array_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ int totalCardinality = src_1->cardinality + src_2->cardinality;
+ if (totalCardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_create_given_capacity(totalCardinality);
+ if (*dst != NULL) {
+ array_container_union(src_1, src_2, (array_container_t *)*dst);
+ } else {
+ return true; // otherwise failure won't be caught
+ }
+ return false; // not a bitset
+ }
+ *dst = bitset_container_create();
+ bool returnval = true; // expect a bitset
+ if (*dst != NULL) {
+ bitset_container_t *ourbitset = (bitset_container_t *)*dst;
+ bitset_set_list(ourbitset->array, src_1->array, src_1->cardinality);
+ ourbitset->cardinality = (int32_t)bitset_set_list_withcard(
+ ourbitset->array, src_1->cardinality, src_2->array,
+ src_2->cardinality);
+ if (ourbitset->cardinality <= DEFAULT_MAX_SIZE) {
+ // need to convert!
+ *dst = array_container_from_bitset(ourbitset);
+ bitset_container_free(ourbitset);
+ returnval = false; // not going to be a bitset
+ }
+ }
+ return returnval;
+}
+
+bool array_array_container_inplace_union(array_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ int totalCardinality = src_1->cardinality + src_2->cardinality;
+ *dst = NULL;
+ if (totalCardinality <= DEFAULT_MAX_SIZE) {
+ if(src_1->capacity < totalCardinality) {
+ *dst = array_container_create_given_capacity(2 * totalCardinality); // be purposefully generous
+ if (*dst != NULL) {
+ array_container_union(src_1, src_2, (array_container_t *)*dst);
+ } else {
+ return true; // otherwise failure won't be caught
+ }
+ return false; // not a bitset
+ } else {
+ memmove(src_1->array + src_2->cardinality, src_1->array, src_1->cardinality * sizeof(uint16_t));
+ src_1->cardinality = (int32_t)union_uint16(src_1->array + src_2->cardinality, src_1->cardinality,
+ src_2->array, src_2->cardinality, src_1->array);
+ return false; // not a bitset
+ }
+ }
+ *dst = bitset_container_create();
+ bool returnval = true; // expect a bitset
+ if (*dst != NULL) {
+ bitset_container_t *ourbitset = (bitset_container_t *)*dst;
+ bitset_set_list(ourbitset->array, src_1->array, src_1->cardinality);
+ ourbitset->cardinality = (int32_t)bitset_set_list_withcard(
+ ourbitset->array, src_1->cardinality, src_2->array,
+ src_2->cardinality);
+ if (ourbitset->cardinality <= DEFAULT_MAX_SIZE) {
+ // need to convert!
+ if(src_1->capacity < ourbitset->cardinality) {
+ array_container_grow(src_1, ourbitset->cardinality, false);
+ }
+
+ bitset_extract_setbits_uint16(ourbitset->array, BITSET_CONTAINER_SIZE_IN_WORDS,
+ src_1->array, 0);
+ src_1->cardinality = ourbitset->cardinality;
+ *dst = src_1;
+ bitset_container_free(ourbitset);
+ returnval = false; // not going to be a bitset
+ }
+ }
+ return returnval;
+}
+
+
+bool array_array_container_lazy_union(const array_container_t *src_1,
+ const array_container_t *src_2,
+ void **dst) {
+ int totalCardinality = src_1->cardinality + src_2->cardinality;
+ if (totalCardinality <= ARRAY_LAZY_LOWERBOUND) {
+ *dst = array_container_create_given_capacity(totalCardinality);
+ if (*dst != NULL) {
+ array_container_union(src_1, src_2, (array_container_t *)*dst);
+ } else {
+ return true; // otherwise failure won't be caught
+ }
+ return false; // not a bitset
+ }
+ *dst = bitset_container_create();
+ bool returnval = true; // expect a bitset
+ if (*dst != NULL) {
+ bitset_container_t *ourbitset = (bitset_container_t *)*dst;
+ bitset_set_list(ourbitset->array, src_1->array, src_1->cardinality);
+ bitset_set_list(ourbitset->array, src_2->array, src_2->cardinality);
+ ourbitset->cardinality = BITSET_UNKNOWN_CARDINALITY;
+ }
+ return returnval;
+}
+
+
+bool array_array_container_lazy_inplace_union(array_container_t *src_1,
+ const array_container_t *src_2,
+ void **dst) {
+ int totalCardinality = src_1->cardinality + src_2->cardinality;
+ *dst = NULL;
+ if (totalCardinality <= ARRAY_LAZY_LOWERBOUND) {
+ if(src_1->capacity < totalCardinality) {
+ *dst = array_container_create_given_capacity(2 * totalCardinality); // be purposefully generous
+ if (*dst != NULL) {
+ array_container_union(src_1, src_2, (array_container_t *)*dst);
+ } else {
+ return true; // otherwise failure won't be caught
+ }
+ return false; // not a bitset
+ } else {
+ memmove(src_1->array + src_2->cardinality, src_1->array, src_1->cardinality * sizeof(uint16_t));
+ src_1->cardinality = (int32_t)union_uint16(src_1->array + src_2->cardinality, src_1->cardinality,
+ src_2->array, src_2->cardinality, src_1->array);
+ return false; // not a bitset
+ }
+ }
+ *dst = bitset_container_create();
+ bool returnval = true; // expect a bitset
+ if (*dst != NULL) {
+ bitset_container_t *ourbitset = (bitset_container_t *)*dst;
+ bitset_set_list(ourbitset->array, src_1->array, src_1->cardinality);
+ bitset_set_list(ourbitset->array, src_2->array, src_2->cardinality);
+ ourbitset->cardinality = BITSET_UNKNOWN_CARDINALITY;
+ }
+ return returnval;
+}
+/* end file src/containers/mixed_union.c */
+/* begin file src/containers/mixed_xor.c */
+/*
+ * mixed_xor.c
+ */
+
+#include
+#include
+
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst (which has no container initially).
+ * Result is true iff dst is a bitset */
+bool array_bitset_container_xor(const array_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ bitset_container_t *result = bitset_container_create();
+ bitset_container_copy(src_2, result);
+ result->cardinality = (int32_t)bitset_flip_list_withcard(
+ result->array, result->cardinality, src_1->array, src_1->cardinality);
+
+ // do required type conversions.
+ if (result->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(result);
+ bitset_container_free(result);
+ return false; // not bitset
+ }
+ *dst = result;
+ return true; // bitset
+}
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst. It is allowed for src_2 to be dst. This version does not
+ * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY).
+ */
+
+void array_bitset_container_lazy_xor(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst) {
+ if (src_2 != dst) bitset_container_copy(src_2, dst);
+ bitset_flip_list(dst->array, src_1->array, src_1->cardinality);
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY;
+}
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_xor(const run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ bitset_container_t *result = bitset_container_create();
+
+ bitset_container_copy(src_2, result);
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ bitset_flip_range(result->array, rle.value,
+ rle.value + rle.length + UINT32_C(1));
+ }
+ result->cardinality = bitset_container_compute_cardinality(result);
+
+ if (result->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(result);
+ bitset_container_free(result);
+ return false; // not bitset
+ }
+ *dst = result;
+ return true; // bitset
+}
+
+/* lazy xor. Dst is initialized and may be equal to src_2.
+ * Result is left as a bitset container, even if actual
+ * cardinality would dictate an array container.
+ */
+
+void run_bitset_container_lazy_xor(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst) {
+ if (src_2 != dst) bitset_container_copy(src_2, dst);
+ for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) {
+ rle16_t rle = src_1->runs[rlepos];
+ bitset_flip_range(dst->array, rle.value,
+ rle.value + rle.length + UINT32_C(1));
+ }
+ dst->cardinality = BITSET_UNKNOWN_CARDINALITY;
+}
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int array_run_container_xor(const array_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ // semi following Java XOR implementation as of May 2016
+ // the C OR implementation works quite differently and can return a run
+ // container
+ // TODO could optimize for full run containers.
+
+ // use of lazy following Java impl.
+ const int arbitrary_threshold = 32;
+ if (src_1->cardinality < arbitrary_threshold) {
+ run_container_t *ans = run_container_create();
+ array_run_container_lazy_xor(src_1, src_2, ans); // keeps runs.
+ uint8_t typecode_after;
+ *dst =
+ convert_run_to_efficient_container_and_free(ans, &typecode_after);
+ return typecode_after;
+ }
+
+ int card = run_container_cardinality(src_2);
+ if (card <= DEFAULT_MAX_SIZE) {
+ // Java implementation works with the array, xoring the run elements via
+ // iterator
+ array_container_t *temp = array_container_from_run(src_2);
+ bool ret_is_bitset = array_array_container_xor(temp, src_1, dst);
+ array_container_free(temp);
+ return ret_is_bitset ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+
+ } else { // guess that it will end up as a bitset
+ bitset_container_t *result = bitset_container_from_run(src_2);
+ bool is_bitset = bitset_array_container_ixor(result, src_1, dst);
+ // any necessary type conversion has been done by the ixor
+ int retval = (is_bitset ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE);
+ return retval;
+ }
+}
+
+/* Dst is a valid run container. (Can it be src_2? Let's say not.)
+ * Leaves result as run container, even if other options are
+ * smaller.
+ */
+
+void array_run_container_lazy_xor(const array_container_t *src_1,
+ const run_container_t *src_2,
+ run_container_t *dst) {
+ run_container_grow(dst, src_1->cardinality + src_2->n_runs, false);
+ int32_t rlepos = 0;
+ int32_t arraypos = 0;
+ dst->n_runs = 0;
+
+ while ((rlepos < src_2->n_runs) && (arraypos < src_1->cardinality)) {
+ if (src_2->runs[rlepos].value <= src_1->array[arraypos]) {
+ run_container_smart_append_exclusive(dst, src_2->runs[rlepos].value,
+ src_2->runs[rlepos].length);
+ rlepos++;
+ } else {
+ run_container_smart_append_exclusive(dst, src_1->array[arraypos],
+ 0);
+ arraypos++;
+ }
+ }
+ while (arraypos < src_1->cardinality) {
+ run_container_smart_append_exclusive(dst, src_1->array[arraypos], 0);
+ arraypos++;
+ }
+ while (rlepos < src_2->n_runs) {
+ run_container_smart_append_exclusive(dst, src_2->runs[rlepos].value,
+ src_2->runs[rlepos].length);
+ rlepos++;
+ }
+}
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int run_run_container_xor(const run_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ run_container_t *ans = run_container_create();
+ run_container_xor(src_1, src_2, ans);
+ uint8_t typecode_after;
+ *dst = convert_run_to_efficient_container_and_free(ans, &typecode_after);
+ return typecode_after;
+}
+
+/*
+ * Java implementation (as of May 2016) for array_run, run_run
+ * and bitset_run don't do anything different for inplace.
+ * Could adopt the mixed_union.c approach instead (ie, using
+ * smart_append_exclusive)
+ *
+ */
+
+bool array_array_container_xor(const array_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ int totalCardinality =
+ src_1->cardinality + src_2->cardinality; // upper bound
+ if (totalCardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_create_given_capacity(totalCardinality);
+ array_container_xor(src_1, src_2, (array_container_t *)*dst);
+ return false; // not a bitset
+ }
+ *dst = bitset_container_from_array(src_1);
+ bool returnval = true; // expect a bitset
+ bitset_container_t *ourbitset = (bitset_container_t *)*dst;
+ ourbitset->cardinality = (uint32_t)bitset_flip_list_withcard(
+ ourbitset->array, src_1->cardinality, src_2->array, src_2->cardinality);
+ if (ourbitset->cardinality <= DEFAULT_MAX_SIZE) {
+ // need to convert!
+ *dst = array_container_from_bitset(ourbitset);
+ bitset_container_free(ourbitset);
+ returnval = false; // not going to be a bitset
+ }
+
+ return returnval;
+}
+
+bool array_array_container_lazy_xor(const array_container_t *src_1,
+ const array_container_t *src_2,
+ void **dst) {
+ int totalCardinality = src_1->cardinality + src_2->cardinality;
+ // upper bound, but probably poor estimate for xor
+ if (totalCardinality <= ARRAY_LAZY_LOWERBOUND) {
+ *dst = array_container_create_given_capacity(totalCardinality);
+ if (*dst != NULL)
+ array_container_xor(src_1, src_2, (array_container_t *)*dst);
+ return false; // not a bitset
+ }
+ *dst = bitset_container_from_array(src_1);
+ bool returnval = true; // expect a bitset (maybe, for XOR??)
+ if (*dst != NULL) {
+ bitset_container_t *ourbitset = (bitset_container_t *)*dst;
+ bitset_flip_list(ourbitset->array, src_2->array, src_2->cardinality);
+ ourbitset->cardinality = BITSET_UNKNOWN_CARDINALITY;
+ }
+ return returnval;
+}
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst (which has no container initially). Return value is
+ * "dst is a bitset"
+ */
+
+bool bitset_bitset_container_xor(const bitset_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ bitset_container_t *ans = bitset_container_create();
+ int card = bitset_container_xor(src_1, src_2, ans);
+ if (card <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(ans);
+ bitset_container_free(ans);
+ return false; // not bitset
+ } else {
+ *dst = ans;
+ return true;
+ }
+}
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_array_container_ixor(bitset_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ *dst = src_1;
+ src_1->cardinality = (uint32_t)bitset_flip_list_withcard(
+ src_1->array, src_1->cardinality, src_2->array, src_2->cardinality);
+
+ if (src_1->cardinality <= DEFAULT_MAX_SIZE) {
+ *dst = array_container_from_bitset(src_1);
+ bitset_container_free(src_1);
+ return false; // not bitset
+ } else
+ return true;
+}
+
+/* a bunch of in-place, some of which may not *really* be inplace.
+ * TODO: write actual inplace routine if efficiency warrants it
+ * Anything inplace with a bitset is a good candidate
+ */
+
+bool bitset_bitset_container_ixor(bitset_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ bool ans = bitset_bitset_container_xor(src_1, src_2, dst);
+ bitset_container_free(src_1);
+ return ans;
+}
+
+bool array_bitset_container_ixor(array_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ bool ans = array_bitset_container_xor(src_1, src_2, dst);
+ array_container_free(src_1);
+ return ans;
+}
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_ixor(run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst) {
+ bool ans = run_bitset_container_xor(src_1, src_2, dst);
+ run_container_free(src_1);
+ return ans;
+}
+
+bool bitset_run_container_ixor(bitset_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ bool ans = run_bitset_container_xor(src_2, src_1, dst);
+ bitset_container_free(src_1);
+ return ans;
+}
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int array_run_container_ixor(array_container_t *src_1,
+ const run_container_t *src_2, void **dst) {
+ int ans = array_run_container_xor(src_1, src_2, dst);
+ array_container_free(src_1);
+ return ans;
+}
+
+int run_array_container_ixor(run_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ int ans = array_run_container_xor(src_2, src_1, dst);
+ run_container_free(src_1);
+ return ans;
+}
+
+bool array_array_container_ixor(array_container_t *src_1,
+ const array_container_t *src_2, void **dst) {
+ bool ans = array_array_container_xor(src_1, src_2, dst);
+ array_container_free(src_1);
+ return ans;
+}
+
+int run_run_container_ixor(run_container_t *src_1, const run_container_t *src_2,
+ void **dst) {
+ int ans = run_run_container_xor(src_1, src_2, dst);
+ run_container_free(src_1);
+ return ans;
+}
+/* end file src/containers/mixed_xor.c */
+/* begin file src/containers/run.c */
+#include
+#include
+
+
+bool run_container_add(run_container_t *run, uint16_t pos) {
+ int32_t index = interleavedBinarySearch(run->runs, run->n_runs, pos);
+ if (index >= 0) return false; // already there
+ index = -index - 2; // points to preceding value, possibly -1
+ if (index >= 0) { // possible match
+ int32_t offset = pos - run->runs[index].value;
+ int32_t le = run->runs[index].length;
+ if (offset <= le) return false; // already there
+ if (offset == le + 1) {
+ // we may need to fuse
+ if (index + 1 < run->n_runs) {
+ if (run->runs[index + 1].value == pos + 1) {
+ // indeed fusion is needed
+ run->runs[index].length = run->runs[index + 1].value +
+ run->runs[index + 1].length -
+ run->runs[index].value;
+ recoverRoomAtIndex(run, (uint16_t)(index + 1));
+ return true;
+ }
+ }
+ run->runs[index].length++;
+ return true;
+ }
+ if (index + 1 < run->n_runs) {
+ // we may need to fuse
+ if (run->runs[index + 1].value == pos + 1) {
+ // indeed fusion is needed
+ run->runs[index + 1].value = pos;
+ run->runs[index + 1].length = run->runs[index + 1].length + 1;
+ return true;
+ }
+ }
+ }
+ if (index == -1) {
+ // we may need to extend the first run
+ if (0 < run->n_runs) {
+ if (run->runs[0].value == pos + 1) {
+ run->runs[0].length++;
+ run->runs[0].value--;
+ return true;
+ }
+ }
+ }
+ makeRoomAtIndex(run, (uint16_t)(index + 1));
+ run->runs[index + 1].value = pos;
+ run->runs[index + 1].length = 0;
+ return true;
+}
+
+/* Create a new run container. Return NULL in case of failure. */
+run_container_t *run_container_create_given_capacity(int32_t size) {
+ run_container_t *run;
+ /* Allocate the run container itself. */
+ run = (run_container_t *)malloc(sizeof(run_container_t));
+ assert (run);
+ if (size <= 0) // we don't want to rely on malloc(0)
+ run->runs = NULL;
+ run->runs = (rle16_t *)malloc(sizeof(rle16_t) * size);
+ assert (run->runs);
+ run->capacity = size;
+ run->n_runs = 0;
+ return run;
+}
+
+int run_container_shrink_to_fit(run_container_t *src) {
+ if (src->n_runs == src->capacity) return 0; // nothing to do
+ int savings = src->capacity - src->n_runs;
+ src->capacity = src->n_runs;
+ rle16_t *oldruns = src->runs;
+ src->runs = (rle16_t *)realloc(oldruns, src->capacity * sizeof(rle16_t));
+ return savings;
+}
+/* Create a new run container. Return NULL in case of failure. */
+run_container_t *run_container_create(void) {
+ return run_container_create_given_capacity(RUN_DEFAULT_INIT_SIZE);
+}
+
+run_container_t *run_container_clone(const run_container_t *src) {
+ run_container_t *run = run_container_create_given_capacity(src->capacity);
+ if (run == NULL) return NULL;
+ run->capacity = src->capacity;
+ run->n_runs = src->n_runs;
+ memcpy(run->runs, src->runs, src->n_runs * sizeof(rle16_t));
+ return run;
+}
+
+/* Free memory. */
+void run_container_free(run_container_t *run) {
+ if(run->runs != NULL) {// Jon Strabala reports that some tools complain otherwise
+ free(run->runs);
+ run->runs = NULL; // pedantic
+ }
+ free(run);
+}
+
+void run_container_grow(run_container_t *run, int32_t min, bool copy) {
+ int32_t newCapacity =
+ (run->capacity == 0)
+ ? RUN_DEFAULT_INIT_SIZE
+ : run->capacity < 64 ? run->capacity * 2
+ : run->capacity < 1024 ? run->capacity * 3 / 2
+ : run->capacity * 5 / 4;
+ if (newCapacity < min) newCapacity = min;
+ run->capacity = newCapacity;
+ assert(run->capacity >= min);
+ if (copy) {
+ rle16_t *oldruns = run->runs;
+ run->runs =
+ (rle16_t *)realloc(oldruns, run->capacity * sizeof(rle16_t));
+ } else {
+ // Jon Strabala reports that some tools complain otherwise
+ if (run->runs != NULL) {
+ free(run->runs);
+ }
+ run->runs = (rle16_t *)malloc(run->capacity * sizeof(rle16_t));
+ }
+ // handle the case where realloc fails
+ if (run->runs == NULL) {
+ fprintf(stderr, "could not allocate memory\n");
+ }
+ assert(run->runs != NULL);
+}
+
+/* copy one container into another */
+void run_container_copy(const run_container_t *src, run_container_t *dst) {
+ const int32_t n_runs = src->n_runs;
+ if (src->n_runs > dst->capacity) {
+ run_container_grow(dst, n_runs, false);
+ }
+ dst->n_runs = n_runs;
+ memcpy(dst->runs, src->runs, sizeof(rle16_t) * n_runs);
+}
+
+/* Compute the union of `src_1' and `src_2' and write the result to `dst'
+ * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
+void run_container_union(const run_container_t *src_1,
+ const run_container_t *src_2, run_container_t *dst) {
+ // TODO: this could be a lot more efficient
+
+ // we start out with inexpensive checks
+ const bool if1 = run_container_is_full(src_1);
+ const bool if2 = run_container_is_full(src_2);
+ if (if1 || if2) {
+ if (if1) {
+ run_container_copy(src_1, dst);
+ return;
+ }
+ if (if2) {
+ run_container_copy(src_2, dst);
+ return;
+ }
+ }
+ const int32_t neededcapacity = src_1->n_runs + src_2->n_runs;
+ if (dst->capacity < neededcapacity)
+ run_container_grow(dst, neededcapacity, false);
+ dst->n_runs = 0;
+ int32_t rlepos = 0;
+ int32_t xrlepos = 0;
+
+ rle16_t previousrle;
+ if (src_1->runs[rlepos].value <= src_2->runs[xrlepos].value) {
+ previousrle = run_container_append_first(dst, src_1->runs[rlepos]);
+ rlepos++;
+ } else {
+ previousrle = run_container_append_first(dst, src_2->runs[xrlepos]);
+ xrlepos++;
+ }
+
+ while ((xrlepos < src_2->n_runs) && (rlepos < src_1->n_runs)) {
+ rle16_t newrl;
+ if (src_1->runs[rlepos].value <= src_2->runs[xrlepos].value) {
+ newrl = src_1->runs[rlepos];
+ rlepos++;
+ } else {
+ newrl = src_2->runs[xrlepos];
+ xrlepos++;
+ }
+ run_container_append(dst, newrl, &previousrle);
+ }
+ while (xrlepos < src_2->n_runs) {
+ run_container_append(dst, src_2->runs[xrlepos], &previousrle);
+ xrlepos++;
+ }
+ while (rlepos < src_1->n_runs) {
+ run_container_append(dst, src_1->runs[rlepos], &previousrle);
+ rlepos++;
+ }
+}
+
+/* Compute the union of `src_1' and `src_2' and write the result to `src_1'
+ */
+void run_container_union_inplace(run_container_t *src_1,
+ const run_container_t *src_2) {
+ // TODO: this could be a lot more efficient
+
+ // we start out with inexpensive checks
+ const bool if1 = run_container_is_full(src_1);
+ const bool if2 = run_container_is_full(src_2);
+ if (if1 || if2) {
+ if (if1) {
+ return;
+ }
+ if (if2) {
+ run_container_copy(src_2, src_1);
+ return;
+ }
+ }
+ // we move the data to the end of the current array
+ const int32_t maxoutput = src_1->n_runs + src_2->n_runs;
+ const int32_t neededcapacity = maxoutput + src_1->n_runs;
+ if (src_1->capacity < neededcapacity)
+ run_container_grow(src_1, neededcapacity, true);
+ memmove(src_1->runs + maxoutput, src_1->runs,
+ src_1->n_runs * sizeof(rle16_t));
+ rle16_t *inputsrc1 = src_1->runs + maxoutput;
+ const int32_t input1nruns = src_1->n_runs;
+ src_1->n_runs = 0;
+ int32_t rlepos = 0;
+ int32_t xrlepos = 0;
+
+ rle16_t previousrle;
+ if (inputsrc1[rlepos].value <= src_2->runs[xrlepos].value) {
+ previousrle = run_container_append_first(src_1, inputsrc1[rlepos]);
+ rlepos++;
+ } else {
+ previousrle = run_container_append_first(src_1, src_2->runs[xrlepos]);
+ xrlepos++;
+ }
+ while ((xrlepos < src_2->n_runs) && (rlepos < input1nruns)) {
+ rle16_t newrl;
+ if (inputsrc1[rlepos].value <= src_2->runs[xrlepos].value) {
+ newrl = inputsrc1[rlepos];
+ rlepos++;
+ } else {
+ newrl = src_2->runs[xrlepos];
+ xrlepos++;
+ }
+ run_container_append(src_1, newrl, &previousrle);
+ }
+ while (xrlepos < src_2->n_runs) {
+ run_container_append(src_1, src_2->runs[xrlepos], &previousrle);
+ xrlepos++;
+ }
+ while (rlepos < input1nruns) {
+ run_container_append(src_1, inputsrc1[rlepos], &previousrle);
+ rlepos++;
+ }
+}
+
+/* Compute the symmetric difference of `src_1' and `src_2' and write the result
+ * to `dst'
+ * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
+void run_container_xor(const run_container_t *src_1,
+ const run_container_t *src_2, run_container_t *dst) {
+ // don't bother to convert xor with full range into negation
+ // since negation is implemented similarly
+
+ const int32_t neededcapacity = src_1->n_runs + src_2->n_runs;
+ if (dst->capacity < neededcapacity)
+ run_container_grow(dst, neededcapacity, false);
+
+ int32_t pos1 = 0;
+ int32_t pos2 = 0;
+ dst->n_runs = 0;
+
+ while ((pos1 < src_1->n_runs) && (pos2 < src_2->n_runs)) {
+ if (src_1->runs[pos1].value <= src_2->runs[pos2].value) {
+ run_container_smart_append_exclusive(dst, src_1->runs[pos1].value,
+ src_1->runs[pos1].length);
+ pos1++;
+ } else {
+ run_container_smart_append_exclusive(dst, src_2->runs[pos2].value,
+ src_2->runs[pos2].length);
+ pos2++;
+ }
+ }
+ while (pos1 < src_1->n_runs) {
+ run_container_smart_append_exclusive(dst, src_1->runs[pos1].value,
+ src_1->runs[pos1].length);
+ pos1++;
+ }
+
+ while (pos2 < src_2->n_runs) {
+ run_container_smart_append_exclusive(dst, src_2->runs[pos2].value,
+ src_2->runs[pos2].length);
+ pos2++;
+ }
+}
+
+/* Compute the intersection of src_1 and src_2 and write the result to
+ * dst. It is assumed that dst is distinct from both src_1 and src_2. */
+void run_container_intersection(const run_container_t *src_1,
+ const run_container_t *src_2,
+ run_container_t *dst) {
+ const bool if1 = run_container_is_full(src_1);
+ const bool if2 = run_container_is_full(src_2);
+ if (if1 || if2) {
+ if (if1) {
+ run_container_copy(src_2, dst);
+ return;
+ }
+ if (if2) {
+ run_container_copy(src_1, dst);
+ return;
+ }
+ }
+ // TODO: this could be a lot more efficient, could use SIMD optimizations
+ const int32_t neededcapacity = src_1->n_runs + src_2->n_runs;
+ if (dst->capacity < neededcapacity)
+ run_container_grow(dst, neededcapacity, false);
+ dst->n_runs = 0;
+ int32_t rlepos = 0;
+ int32_t xrlepos = 0;
+ int32_t start = src_1->runs[rlepos].value;
+ int32_t end = start + src_1->runs[rlepos].length + 1;
+ int32_t xstart = src_2->runs[xrlepos].value;
+ int32_t xend = xstart + src_2->runs[xrlepos].length + 1;
+ while ((rlepos < src_1->n_runs) && (xrlepos < src_2->n_runs)) {
+ if (end <= xstart) {
+ ++rlepos;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ } else if (xend <= start) {
+ ++xrlepos;
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ } else { // they overlap
+ const int32_t lateststart = start > xstart ? start : xstart;
+ int32_t earliestend;
+ if (end == xend) { // improbable
+ earliestend = end;
+ rlepos++;
+ xrlepos++;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ } else if (end < xend) {
+ earliestend = end;
+ rlepos++;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+
+ } else { // end > xend
+ earliestend = xend;
+ xrlepos++;
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ }
+ dst->runs[dst->n_runs].value = (uint16_t)lateststart;
+ dst->runs[dst->n_runs].length =
+ (uint16_t)(earliestend - lateststart - 1);
+ dst->n_runs++;
+ }
+ }
+}
+
+/* Compute the size of the intersection of src_1 and src_2 . */
+int run_container_intersection_cardinality(const run_container_t *src_1,
+ const run_container_t *src_2) {
+ const bool if1 = run_container_is_full(src_1);
+ const bool if2 = run_container_is_full(src_2);
+ if (if1 || if2) {
+ if (if1) {
+ return run_container_cardinality(src_2);
+ }
+ if (if2) {
+ return run_container_cardinality(src_1);
+ }
+ }
+ int answer = 0;
+ int32_t rlepos = 0;
+ int32_t xrlepos = 0;
+ int32_t start = src_1->runs[rlepos].value;
+ int32_t end = start + src_1->runs[rlepos].length + 1;
+ int32_t xstart = src_2->runs[xrlepos].value;
+ int32_t xend = xstart + src_2->runs[xrlepos].length + 1;
+ while ((rlepos < src_1->n_runs) && (xrlepos < src_2->n_runs)) {
+ if (end <= xstart) {
+ ++rlepos;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ } else if (xend <= start) {
+ ++xrlepos;
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ } else { // they overlap
+ const int32_t lateststart = start > xstart ? start : xstart;
+ int32_t earliestend;
+ if (end == xend) { // improbable
+ earliestend = end;
+ rlepos++;
+ xrlepos++;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ } else if (end < xend) {
+ earliestend = end;
+ rlepos++;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+
+ } else { // end > xend
+ earliestend = xend;
+ xrlepos++;
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ }
+ answer += earliestend - lateststart;
+ }
+ }
+ return answer;
+}
+
+bool run_container_intersect(const run_container_t *src_1,
+ const run_container_t *src_2) {
+ const bool if1 = run_container_is_full(src_1);
+ const bool if2 = run_container_is_full(src_2);
+ if (if1 || if2) {
+ if (if1) {
+ return !run_container_empty(src_2);
+ }
+ if (if2) {
+ return !run_container_empty(src_1);
+ }
+ }
+ int32_t rlepos = 0;
+ int32_t xrlepos = 0;
+ int32_t start = src_1->runs[rlepos].value;
+ int32_t end = start + src_1->runs[rlepos].length + 1;
+ int32_t xstart = src_2->runs[xrlepos].value;
+ int32_t xend = xstart + src_2->runs[xrlepos].length + 1;
+ while ((rlepos < src_1->n_runs) && (xrlepos < src_2->n_runs)) {
+ if (end <= xstart) {
+ ++rlepos;
+ if (rlepos < src_1->n_runs) {
+ start = src_1->runs[rlepos].value;
+ end = start + src_1->runs[rlepos].length + 1;
+ }
+ } else if (xend <= start) {
+ ++xrlepos;
+ if (xrlepos < src_2->n_runs) {
+ xstart = src_2->runs[xrlepos].value;
+ xend = xstart + src_2->runs[xrlepos].length + 1;
+ }
+ } else { // they overlap
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/* Compute the difference of src_1 and src_2 and write the result to
+ * dst. It is assumed that dst is distinct from both src_1 and src_2. */
+void run_container_andnot(const run_container_t *src_1,
+ const run_container_t *src_2, run_container_t *dst) {
+ // following Java implementation as of June 2016
+
+ if (dst->capacity < src_1->n_runs + src_2->n_runs)
+ run_container_grow(dst, src_1->n_runs + src_2->n_runs, false);
+
+ dst->n_runs = 0;
+
+ int rlepos1 = 0;
+ int rlepos2 = 0;
+ int32_t start = src_1->runs[rlepos1].value;
+ int32_t end = start + src_1->runs[rlepos1].length + 1;
+ int32_t start2 = src_2->runs[rlepos2].value;
+ int32_t end2 = start2 + src_2->runs[rlepos2].length + 1;
+
+ while ((rlepos1 < src_1->n_runs) && (rlepos2 < src_2->n_runs)) {
+ if (end <= start2) {
+ // output the first run
+ dst->runs[dst->n_runs++] =
+ (rle16_t){.value = (uint16_t)start,
+ .length = (uint16_t)(end - start - 1)};
+ rlepos1++;
+ if (rlepos1 < src_1->n_runs) {
+ start = src_1->runs[rlepos1].value;
+ end = start + src_1->runs[rlepos1].length + 1;
+ }
+ } else if (end2 <= start) {
+ // exit the second run
+ rlepos2++;
+ if (rlepos2 < src_2->n_runs) {
+ start2 = src_2->runs[rlepos2].value;
+ end2 = start2 + src_2->runs[rlepos2].length + 1;
+ }
+ } else {
+ if (start < start2) {
+ dst->runs[dst->n_runs++] =
+ (rle16_t){.value = (uint16_t)start,
+ .length = (uint16_t)(start2 - start - 1)};
+ }
+ if (end2 < end) {
+ start = end2;
+ } else {
+ rlepos1++;
+ if (rlepos1 < src_1->n_runs) {
+ start = src_1->runs[rlepos1].value;
+ end = start + src_1->runs[rlepos1].length + 1;
+ }
+ }
+ }
+ }
+ if (rlepos1 < src_1->n_runs) {
+ dst->runs[dst->n_runs++] = (rle16_t){
+ .value = (uint16_t)start, .length = (uint16_t)(end - start - 1)};
+ rlepos1++;
+ if (rlepos1 < src_1->n_runs) {
+ memcpy(dst->runs + dst->n_runs, src_1->runs + rlepos1,
+ sizeof(rle16_t) * (src_1->n_runs - rlepos1));
+ dst->n_runs += src_1->n_runs - rlepos1;
+ }
+ }
+}
+
+int run_container_to_uint32_array(void *vout, const run_container_t *cont,
+ uint32_t base) {
+ int outpos = 0;
+ uint32_t *out = (uint32_t *)vout;
+ for (int i = 0; i < cont->n_runs; ++i) {
+ uint32_t run_start = base + cont->runs[i].value;
+ uint16_t le = cont->runs[i].length;
+ for (int j = 0; j <= le; ++j) {
+ uint32_t val = run_start + j;
+ memcpy(out + outpos, &val,
+ sizeof(uint32_t)); // should be compiled as a MOV on x64
+ outpos++;
+ }
+ }
+ return outpos;
+}
+
+/*
+ * Print this container using printf (useful for debugging).
+ */
+void run_container_printf(const run_container_t *cont) {
+ for (int i = 0; i < cont->n_runs; ++i) {
+ uint16_t run_start = cont->runs[i].value;
+ uint16_t le = cont->runs[i].length;
+ printf("[%d,%d]", run_start, run_start + le);
+ }
+}
+
+/*
+ * Print this container using printf as a comma-separated list of 32-bit
+ * integers starting at base.
+ */
+void run_container_printf_as_uint32_array(const run_container_t *cont,
+ uint32_t base) {
+ if (cont->n_runs == 0) return;
+ {
+ uint32_t run_start = base + cont->runs[0].value;
+ uint16_t le = cont->runs[0].length;
+ printf("%u", run_start);
+ for (uint32_t j = 1; j <= le; ++j) printf(",%u", run_start + j);
+ }
+ for (int32_t i = 1; i < cont->n_runs; ++i) {
+ uint32_t run_start = base + cont->runs[i].value;
+ uint16_t le = cont->runs[i].length;
+ for (uint32_t j = 0; j <= le; ++j) printf(",%u", run_start + j);
+ }
+}
+
+int32_t run_container_serialize(const run_container_t *container, char *buf) {
+ int32_t l, off;
+
+ memcpy(buf, &container->n_runs, off = sizeof(container->n_runs));
+ memcpy(&buf[off], &container->capacity, sizeof(container->capacity));
+ off += sizeof(container->capacity);
+
+ l = sizeof(rle16_t) * container->n_runs;
+ memcpy(&buf[off], container->runs, l);
+ return (off + l);
+}
+
+int32_t run_container_write(const run_container_t *container, char *buf) {
+ memcpy(buf, &container->n_runs, sizeof(uint16_t));
+ memcpy(buf + sizeof(uint16_t), container->runs,
+ container->n_runs * sizeof(rle16_t));
+ return run_container_size_in_bytes(container);
+}
+
+int32_t run_container_read(int32_t cardinality, run_container_t *container,
+ const char *buf) {
+ (void)cardinality;
+ memcpy(&container->n_runs, buf, sizeof(uint16_t));
+ if (container->n_runs > container->capacity)
+ run_container_grow(container, container->n_runs, false);
+ if(container->n_runs > 0) {
+ memcpy(container->runs, buf + sizeof(uint16_t),
+ container->n_runs * sizeof(rle16_t));
+ }
+ return run_container_size_in_bytes(container);
+}
+
+uint32_t run_container_serialization_len(const run_container_t *container) {
+ return (sizeof(container->n_runs) + sizeof(container->capacity) +
+ sizeof(rle16_t) * container->n_runs);
+}
+
+void *run_container_deserialize(const char *buf, size_t buf_len) {
+ run_container_t *ptr;
+
+ if (buf_len < 8 /* n_runs + capacity */)
+ return (NULL);
+ else
+ buf_len -= 8;
+
+ if ((ptr = (run_container_t *)malloc(sizeof(run_container_t))) != NULL) {
+ size_t len;
+ int32_t off;
+
+ memcpy(&ptr->n_runs, buf, off = 4);
+ memcpy(&ptr->capacity, &buf[off], 4);
+ off += 4;
+
+ len = sizeof(rle16_t) * ptr->n_runs;
+
+ if (len != buf_len) {
+ free(ptr);
+ return (NULL);
+ }
+
+ if ((ptr->runs = (rle16_t *)malloc(len)) == NULL) {
+ free(ptr);
+ return (NULL);
+ }
+
+ memcpy(ptr->runs, &buf[off], len);
+
+ /* Check if returned values are monotonically increasing */
+ for (int32_t i = 0, j = 0; i < ptr->n_runs; i++) {
+ if (ptr->runs[i].value < j) {
+ free(ptr->runs);
+ free(ptr);
+ return (NULL);
+ } else
+ j = ptr->runs[i].value;
+ }
+ }
+
+ return (ptr);
+}
+
+bool run_container_iterate(const run_container_t *cont, uint32_t base,
+ roaring_iterator iterator, void *ptr) {
+ for (int i = 0; i < cont->n_runs; ++i) {
+ uint32_t run_start = base + cont->runs[i].value;
+ uint16_t le = cont->runs[i].length;
+
+ for (int j = 0; j <= le; ++j)
+ if (!iterator(run_start + j, ptr)) return false;
+ }
+ return true;
+}
+
+bool run_container_iterate64(const run_container_t *cont, uint32_t base,
+ roaring_iterator64 iterator, uint64_t high_bits,
+ void *ptr) {
+ for (int i = 0; i < cont->n_runs; ++i) {
+ uint32_t run_start = base + cont->runs[i].value;
+ uint16_t le = cont->runs[i].length;
+
+ for (int j = 0; j <= le; ++j)
+ if (!iterator(high_bits | (uint64_t)(run_start + j), ptr))
+ return false;
+ }
+ return true;
+}
+
+bool run_container_is_subset(const run_container_t *container1,
+ const run_container_t *container2) {
+ int i1 = 0, i2 = 0;
+ while (i1 < container1->n_runs && i2 < container2->n_runs) {
+ int start1 = container1->runs[i1].value;
+ int stop1 = start1 + container1->runs[i1].length;
+ int start2 = container2->runs[i2].value;
+ int stop2 = start2 + container2->runs[i2].length;
+ if (start1 < start2) {
+ return false;
+ } else { // start1 >= start2
+ if (stop1 < stop2) {
+ i1++;
+ } else if (stop1 == stop2) {
+ i1++;
+ i2++;
+ } else { // stop1 > stop2
+ i2++;
+ }
+ }
+ }
+ if (i1 == container1->n_runs) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// TODO: write smart_append_exclusive version to match the overloaded 1 param
+// Java version (or is it even used?)
+
+// follows the Java implementation closely
+// length is the rle-value. Ie, run [10,12) uses a length value 1.
+void run_container_smart_append_exclusive(run_container_t *src,
+ const uint16_t start,
+ const uint16_t length) {
+ int old_end;
+ rle16_t *last_run = src->n_runs ? src->runs + (src->n_runs - 1) : NULL;
+ rle16_t *appended_last_run = src->runs + src->n_runs;
+
+ if (!src->n_runs ||
+ (start > (old_end = last_run->value + last_run->length + 1))) {
+ *appended_last_run = (rle16_t){.value = start, .length = length};
+ src->n_runs++;
+ return;
+ }
+ if (old_end == start) {
+ // we merge
+ last_run->length += (length + 1);
+ return;
+ }
+ int new_end = start + length + 1;
+
+ if (start == last_run->value) {
+ // wipe out previous
+ if (new_end < old_end) {
+ *last_run = (rle16_t){.value = (uint16_t)new_end,
+ .length = (uint16_t)(old_end - new_end - 1)};
+ return;
+ } else if (new_end > old_end) {
+ *last_run = (rle16_t){.value = (uint16_t)old_end,
+ .length = (uint16_t)(new_end - old_end - 1)};
+ return;
+ } else {
+ src->n_runs--;
+ return;
+ }
+ }
+ last_run->length = start - last_run->value - 1;
+ if (new_end < old_end) {
+ *appended_last_run =
+ (rle16_t){.value = (uint16_t)new_end,
+ .length = (uint16_t)(old_end - new_end - 1)};
+ src->n_runs++;
+ } else if (new_end > old_end) {
+ *appended_last_run =
+ (rle16_t){.value = (uint16_t)old_end,
+ .length = (uint16_t)(new_end - old_end - 1)};
+ src->n_runs++;
+ }
+}
+
+bool run_container_select(const run_container_t *container,
+ uint32_t *start_rank, uint32_t rank,
+ uint32_t *element) {
+ for (int i = 0; i < container->n_runs; i++) {
+ uint16_t length = container->runs[i].length;
+ if (rank <= *start_rank + length) {
+ uint16_t value = container->runs[i].value;
+ *element = value + rank - (*start_rank);
+ return true;
+ } else
+ *start_rank += length + 1;
+ }
+ return false;
+}
+
+int run_container_rank(const run_container_t *container, uint16_t x) {
+ int sum = 0;
+ uint32_t x32 = x;
+ for (int i = 0; i < container->n_runs; i++) {
+ uint32_t startpoint = container->runs[i].value;
+ uint32_t length = container->runs[i].length;
+ uint32_t endpoint = length + startpoint;
+ if (x <= endpoint) {
+ if (x < startpoint) break;
+ return sum + (x32 - startpoint) + 1;
+ } else {
+ sum += length + 1;
+ }
+ }
+ return sum;
+}
+/* end file src/containers/run.c */
+/* begin file src/roaring.c */
+#include
+#include
+#include
+#include
+#include
+#include
+
+static inline bool is_cow(const roaring_bitmap_t *r) {
+ return r->high_low_container.flags & ROARING_FLAG_COW;
+}
+static inline bool is_frozen(const roaring_bitmap_t *r) {
+ return r->high_low_container.flags & ROARING_FLAG_FROZEN;
+}
+
+// this is like roaring_bitmap_add, but it populates pointer arguments in such a
+// way
+// that we can recover the container touched, which, in turn can be used to
+// accelerate some functions (when you repeatedly need to add to the same
+// container)
+static inline void *containerptr_roaring_bitmap_add(roaring_bitmap_t *r,
+ uint32_t val,
+ uint8_t *typecode,
+ int *index) {
+ uint16_t hb = val >> 16;
+ const int i = ra_get_index(&r->high_low_container, hb);
+ if (i >= 0) {
+ ra_unshare_container_at_index(&r->high_low_container, i);
+ void *container =
+ ra_get_container_at_index(&r->high_low_container, i, typecode);
+ uint8_t newtypecode = *typecode;
+ void *container2 =
+ container_add(container, val & 0xFFFF, *typecode, &newtypecode);
+ *index = i;
+ if (container2 != container) {
+ container_free(container, *typecode);
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ *typecode = newtypecode;
+ return container2;
+ } else {
+ return container;
+ }
+ } else {
+ array_container_t *newac = array_container_create();
+ void *container = container_add(newac, val & 0xFFFF,
+ ARRAY_CONTAINER_TYPE_CODE, typecode);
+ // we could just assume that it stays an array container
+ ra_insert_new_key_value_at(&r->high_low_container, -i - 1, hb,
+ container, *typecode);
+ *index = -i - 1;
+ return container;
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_create(void) {
+ roaring_bitmap_t *ans =
+ (roaring_bitmap_t *)malloc(sizeof(roaring_bitmap_t));
+ if (!ans) {
+ return NULL;
+ }
+ ra_init(&ans->high_low_container);
+ return ans;
+}
+
+roaring_bitmap_t *roaring_bitmap_create_with_capacity(uint32_t cap) {
+ roaring_bitmap_t *ans =
+ (roaring_bitmap_t *)malloc(sizeof(roaring_bitmap_t));
+ if (!ans) {
+ return NULL;
+ }
+ bool is_ok = ra_init_with_capacity(&ans->high_low_container, cap);
+ if (!is_ok) {
+ free(ans);
+ return NULL;
+ }
+ return ans;
+}
+
+void roaring_bitmap_add_many(roaring_bitmap_t *r, size_t n_args,
+ const uint32_t *vals) {
+ void *container = NULL; // hold value of last container touched
+ uint8_t typecode = 0; // typecode of last container touched
+ uint32_t prev = 0; // previous valued inserted
+ size_t i = 0; // index of value
+ int containerindex = 0;
+ if (n_args == 0) return;
+ uint32_t val;
+ memcpy(&val, vals + i, sizeof(val));
+ container =
+ containerptr_roaring_bitmap_add(r, val, &typecode, &containerindex);
+ prev = val;
+ i++;
+ for (; i < n_args; i++) {
+ memcpy(&val, vals + i, sizeof(val));
+ if (((prev ^ val) >> 16) ==
+ 0) { // no need to seek the container, it is at hand
+ // because we already have the container at hand, we can do the
+ // insertion
+ // automatically, bypassing the roaring_bitmap_add call
+ uint8_t newtypecode = typecode;
+ void *container2 =
+ container_add(container, val & 0xFFFF, typecode, &newtypecode);
+ if (container2 != container) { // rare instance when we need to
+ // change the container type
+ container_free(container, typecode);
+ ra_set_container_at_index(&r->high_low_container,
+ containerindex, container2,
+ newtypecode);
+ typecode = newtypecode;
+ container = container2;
+ }
+ } else {
+ container = containerptr_roaring_bitmap_add(r, val, &typecode,
+ &containerindex);
+ }
+ prev = val;
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_of_ptr(size_t n_args, const uint32_t *vals) {
+ roaring_bitmap_t *answer = roaring_bitmap_create();
+ roaring_bitmap_add_many(answer, n_args, vals);
+ return answer;
+}
+
+roaring_bitmap_t *roaring_bitmap_of(size_t n_args, ...) {
+ // todo: could be greatly optimized but we do not expect this call to ever
+ // include long lists
+ roaring_bitmap_t *answer = roaring_bitmap_create();
+ va_list ap;
+ va_start(ap, n_args);
+ for (size_t i = 1; i <= n_args; i++) {
+ uint32_t val = va_arg(ap, uint32_t);
+ roaring_bitmap_add(answer, val);
+ }
+ va_end(ap);
+ return answer;
+}
+
+static inline uint32_t minimum_uint32(uint32_t a, uint32_t b) {
+ return (a < b) ? a : b;
+}
+
+static inline uint64_t minimum_uint64(uint64_t a, uint64_t b) {
+ return (a < b) ? a : b;
+}
+
+roaring_bitmap_t *roaring_bitmap_from_range(uint64_t min, uint64_t max,
+ uint32_t step) {
+ if(max >= UINT64_C(0x100000000)) {
+ max = UINT64_C(0x100000000);
+ }
+ if (step == 0) return NULL;
+ if (max <= min) return NULL;
+ roaring_bitmap_t *answer = roaring_bitmap_create();
+ if (step >= (1 << 16)) {
+ for (uint32_t value = (uint32_t)min; value < max; value += step) {
+ roaring_bitmap_add(answer, value);
+ }
+ return answer;
+ }
+ uint64_t min_tmp = min;
+ do {
+ uint32_t key = (uint32_t)min_tmp >> 16;
+ uint32_t container_min = min_tmp & 0xFFFF;
+ uint32_t container_max = (uint32_t)minimum_uint64(max - (key << 16), 1 << 16);
+ uint8_t type;
+ void *container = container_from_range(&type, container_min,
+ container_max, (uint16_t)step);
+ ra_append(&answer->high_low_container, key, container, type);
+ uint32_t gap = container_max - container_min + step - 1;
+ min_tmp += gap - (gap % step);
+ } while (min_tmp < max);
+ // cardinality of bitmap will be ((uint64_t) max - min + step - 1 ) / step
+ return answer;
+}
+
+void roaring_bitmap_add_range_closed(roaring_bitmap_t *ra, uint32_t min, uint32_t max) {
+ if (min > max) {
+ return;
+ }
+
+ uint32_t min_key = min >> 16;
+ uint32_t max_key = max >> 16;
+
+ int32_t num_required_containers = max_key - min_key + 1;
+ int32_t suffix_length = count_greater(ra->high_low_container.keys,
+ ra->high_low_container.size,
+ max_key);
+ int32_t prefix_length = count_less(ra->high_low_container.keys,
+ ra->high_low_container.size - suffix_length,
+ min_key);
+ int32_t common_length = ra->high_low_container.size - prefix_length - suffix_length;
+
+ if (num_required_containers > common_length) {
+ ra_shift_tail(&ra->high_low_container, suffix_length,
+ num_required_containers - common_length);
+ }
+
+ int32_t src = prefix_length + common_length - 1;
+ int32_t dst = ra->high_low_container.size - suffix_length - 1;
+ for (uint32_t key = max_key; key != min_key-1; key--) { // beware of min_key==0
+ uint32_t container_min = (min_key == key) ? (min & 0xffff) : 0;
+ uint32_t container_max = (max_key == key) ? (max & 0xffff) : 0xffff;
+ void* new_container;
+ uint8_t new_type;
+
+ if (src >= 0 && ra->high_low_container.keys[src] == key) {
+ ra_unshare_container_at_index(&ra->high_low_container, src);
+ new_container = container_add_range(ra->high_low_container.containers[src],
+ ra->high_low_container.typecodes[src],
+ container_min, container_max, &new_type);
+ if (new_container != ra->high_low_container.containers[src]) {
+ container_free(ra->high_low_container.containers[src],
+ ra->high_low_container.typecodes[src]);
+ }
+ src--;
+ } else {
+ new_container = container_from_range(&new_type, container_min,
+ container_max+1, 1);
+ }
+ ra_replace_key_and_container_at_index(&ra->high_low_container, dst,
+ key, new_container, new_type);
+ dst--;
+ }
+}
+
+void roaring_bitmap_remove_range_closed(roaring_bitmap_t *ra, uint32_t min, uint32_t max) {
+ if (min > max) {
+ return;
+ }
+
+ uint32_t min_key = min >> 16;
+ uint32_t max_key = max >> 16;
+
+ int32_t src = count_less(ra->high_low_container.keys, ra->high_low_container.size, min_key);
+ int32_t dst = src;
+ while (src < ra->high_low_container.size && ra->high_low_container.keys[src] <= max_key) {
+ uint32_t container_min = (min_key == ra->high_low_container.keys[src]) ? (min & 0xffff) : 0;
+ uint32_t container_max = (max_key == ra->high_low_container.keys[src]) ? (max & 0xffff) : 0xffff;
+ ra_unshare_container_at_index(&ra->high_low_container, src);
+ void *new_container;
+ uint8_t new_type;
+ new_container = container_remove_range(ra->high_low_container.containers[src],
+ ra->high_low_container.typecodes[src],
+ container_min, container_max,
+ &new_type);
+ if (new_container != ra->high_low_container.containers[src]) {
+ container_free(ra->high_low_container.containers[src],
+ ra->high_low_container.typecodes[src]);
+ }
+ if (new_container) {
+ ra_replace_key_and_container_at_index(&ra->high_low_container, dst,
+ ra->high_low_container.keys[src],
+ new_container, new_type);
+ dst++;
+ }
+ src++;
+ }
+ if (src > dst) {
+ ra_shift_tail(&ra->high_low_container, ra->high_low_container.size - src, dst - src);
+ }
+}
+
+void roaring_bitmap_printf(const roaring_bitmap_t *ra) {
+ printf("{");
+ for (int i = 0; i < ra->high_low_container.size; ++i) {
+ container_printf_as_uint32_array(
+ ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i],
+ ((uint32_t)ra->high_low_container.keys[i]) << 16);
+ if (i + 1 < ra->high_low_container.size) printf(",");
+ }
+ printf("}");
+}
+
+void roaring_bitmap_printf_describe(const roaring_bitmap_t *ra) {
+ printf("{");
+ for (int i = 0; i < ra->high_low_container.size; ++i) {
+ printf("%d: %s (%d)", ra->high_low_container.keys[i],
+ get_full_container_name(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]),
+ container_get_cardinality(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]));
+ if (ra->high_low_container.typecodes[i] == SHARED_CONTAINER_TYPE_CODE) {
+ printf(
+ "(shared count = %" PRIu32 " )",
+ ((shared_container_t *)(ra->high_low_container.containers[i]))
+ ->counter);
+ }
+
+ if (i + 1 < ra->high_low_container.size) printf(", ");
+ }
+ printf("}");
+}
+
+typedef struct min_max_sum_s {
+ uint32_t min;
+ uint32_t max;
+ uint64_t sum;
+} min_max_sum_t;
+
+static bool min_max_sum_fnc(uint32_t value, void *param) {
+ min_max_sum_t *mms = (min_max_sum_t *)param;
+ if (value > mms->max) mms->max = value;
+ if (value < mms->min) mms->min = value;
+ mms->sum += value;
+ return true; // we always process all data points
+}
+
+/**
+* (For advanced users.)
+* Collect statistics about the bitmap
+*/
+void roaring_bitmap_statistics(const roaring_bitmap_t *ra,
+ roaring_statistics_t *stat) {
+ memset(stat, 0, sizeof(*stat));
+ stat->n_containers = ra->high_low_container.size;
+ stat->cardinality = roaring_bitmap_get_cardinality(ra);
+ min_max_sum_t mms;
+ mms.min = UINT32_C(0xFFFFFFFF);
+ mms.max = UINT32_C(0);
+ mms.sum = 0;
+ roaring_iterate(ra, &min_max_sum_fnc, &mms);
+ stat->min_value = mms.min;
+ stat->max_value = mms.max;
+ stat->sum_value = mms.sum;
+
+ for (int i = 0; i < ra->high_low_container.size; ++i) {
+ uint8_t truetype =
+ get_container_type(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]);
+ uint32_t card =
+ container_get_cardinality(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]);
+ uint32_t sbytes =
+ container_size_in_bytes(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]);
+ switch (truetype) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ stat->n_bitset_containers++;
+ stat->n_values_bitset_containers += card;
+ stat->n_bytes_bitset_containers += sbytes;
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ stat->n_array_containers++;
+ stat->n_values_array_containers += card;
+ stat->n_bytes_array_containers += sbytes;
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ stat->n_run_containers++;
+ stat->n_values_run_containers += card;
+ stat->n_bytes_run_containers += sbytes;
+ break;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ }
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_copy(const roaring_bitmap_t *r) {
+ roaring_bitmap_t *ans =
+ (roaring_bitmap_t *)malloc(sizeof(roaring_bitmap_t));
+ if (!ans) {
+ return NULL;
+ }
+ bool is_ok = ra_copy(&r->high_low_container, &ans->high_low_container,
+ is_cow(r));
+ if (!is_ok) {
+ free(ans);
+ return NULL;
+ }
+ roaring_bitmap_set_copy_on_write(ans, is_cow(r));
+ return ans;
+}
+
+bool roaring_bitmap_overwrite(roaring_bitmap_t *dest,
+ const roaring_bitmap_t *src) {
+ return ra_overwrite(&src->high_low_container, &dest->high_low_container,
+ is_cow(src));
+}
+
+void roaring_bitmap_free(const roaring_bitmap_t *r) {
+ if (!is_frozen(r)) {
+ ra_clear((roaring_array_t*)&r->high_low_container);
+ }
+ free((roaring_bitmap_t*)r);
+}
+
+void roaring_bitmap_clear(roaring_bitmap_t *r) {
+ ra_reset(&r->high_low_container);
+}
+
+void roaring_bitmap_add(roaring_bitmap_t *r, uint32_t val) {
+ const uint16_t hb = val >> 16;
+ const int i = ra_get_index(&r->high_low_container, hb);
+ uint8_t typecode;
+ if (i >= 0) {
+ ra_unshare_container_at_index(&r->high_low_container, i);
+ void *container =
+ ra_get_container_at_index(&r->high_low_container, i, &typecode);
+ uint8_t newtypecode = typecode;
+ void *container2 =
+ container_add(container, val & 0xFFFF, typecode, &newtypecode);
+ if (container2 != container) {
+ container_free(container, typecode);
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ }
+ } else {
+ array_container_t *newac = array_container_create();
+ void *container = container_add(newac, val & 0xFFFF,
+ ARRAY_CONTAINER_TYPE_CODE, &typecode);
+ // we could just assume that it stays an array container
+ ra_insert_new_key_value_at(&r->high_low_container, -i - 1, hb,
+ container, typecode);
+ }
+}
+
+bool roaring_bitmap_add_checked(roaring_bitmap_t *r, uint32_t val) {
+ const uint16_t hb = val >> 16;
+ const int i = ra_get_index(&r->high_low_container, hb);
+ uint8_t typecode;
+ bool result = false;
+ if (i >= 0) {
+ ra_unshare_container_at_index(&r->high_low_container, i);
+ void *container =
+ ra_get_container_at_index(&r->high_low_container, i, &typecode);
+
+ const int oldCardinality =
+ container_get_cardinality(container, typecode);
+
+ uint8_t newtypecode = typecode;
+ void *container2 =
+ container_add(container, val & 0xFFFF, typecode, &newtypecode);
+ if (container2 != container) {
+ container_free(container, typecode);
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ result = true;
+ } else {
+ const int newCardinality =
+ container_get_cardinality(container, newtypecode);
+
+ result = oldCardinality != newCardinality;
+ }
+ } else {
+ array_container_t *newac = array_container_create();
+ void *container = container_add(newac, val & 0xFFFF,
+ ARRAY_CONTAINER_TYPE_CODE, &typecode);
+ // we could just assume that it stays an array container
+ ra_insert_new_key_value_at(&r->high_low_container, -i - 1, hb,
+ container, typecode);
+ result = true;
+ }
+
+ return result;
+}
+
+void roaring_bitmap_remove(roaring_bitmap_t *r, uint32_t val) {
+ const uint16_t hb = val >> 16;
+ const int i = ra_get_index(&r->high_low_container, hb);
+ uint8_t typecode;
+ if (i >= 0) {
+ ra_unshare_container_at_index(&r->high_low_container, i);
+ void *container =
+ ra_get_container_at_index(&r->high_low_container, i, &typecode);
+ uint8_t newtypecode = typecode;
+ void *container2 =
+ container_remove(container, val & 0xFFFF, typecode, &newtypecode);
+ if (container2 != container) {
+ container_free(container, typecode);
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ }
+ if (container_get_cardinality(container2, newtypecode) != 0) {
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ } else {
+ ra_remove_at_index_and_free(&r->high_low_container, i);
+ }
+ }
+}
+
+bool roaring_bitmap_remove_checked(roaring_bitmap_t *r, uint32_t val) {
+ const uint16_t hb = val >> 16;
+ const int i = ra_get_index(&r->high_low_container, hb);
+ uint8_t typecode;
+ bool result = false;
+ if (i >= 0) {
+ ra_unshare_container_at_index(&r->high_low_container, i);
+ void *container =
+ ra_get_container_at_index(&r->high_low_container, i, &typecode);
+
+ const int oldCardinality =
+ container_get_cardinality(container, typecode);
+
+ uint8_t newtypecode = typecode;
+ void *container2 =
+ container_remove(container, val & 0xFFFF, typecode, &newtypecode);
+ if (container2 != container) {
+ container_free(container, typecode);
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ }
+
+ const int newCardinality =
+ container_get_cardinality(container2, newtypecode);
+
+ if (newCardinality != 0) {
+ ra_set_container_at_index(&r->high_low_container, i, container2,
+ newtypecode);
+ } else {
+ ra_remove_at_index_and_free(&r->high_low_container, i);
+ }
+
+ result = oldCardinality != newCardinality;
+ }
+ return result;
+}
+
+void roaring_bitmap_remove_many(roaring_bitmap_t *r, size_t n_args,
+ const uint32_t *vals) {
+ if (n_args == 0 || r->high_low_container.size == 0) {
+ return;
+ }
+ int32_t pos = -1; // position of the container used in the previous iteration
+ for (size_t i = 0; i < n_args; i++) {
+ uint16_t key = (uint16_t)(vals[i] >> 16);
+ if (pos < 0 || key != r->high_low_container.keys[pos]) {
+ pos = ra_get_index(&r->high_low_container, key);
+ }
+ if (pos >= 0) {
+ uint8_t new_typecode;
+ void *new_container;
+ new_container = container_remove(r->high_low_container.containers[pos],
+ vals[i] & 0xffff,
+ r->high_low_container.typecodes[pos],
+ &new_typecode);
+ if (new_container != r->high_low_container.containers[pos]) {
+ container_free(r->high_low_container.containers[pos],
+ r->high_low_container.typecodes[pos]);
+ ra_replace_key_and_container_at_index(&r->high_low_container,
+ pos, key, new_container,
+ new_typecode);
+ }
+ if (!container_nonzero_cardinality(new_container, new_typecode)) {
+ container_free(new_container, new_typecode);
+ ra_remove_at_index(&r->high_low_container, pos);
+ pos = -1;
+ }
+ }
+ }
+}
+
+// there should be some SIMD optimizations possible here
+roaring_bitmap_t *roaring_bitmap_and(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ uint32_t neededcap = length1 > length2 ? length2 : length1;
+ roaring_bitmap_t *answer = roaring_bitmap_create_with_capacity(neededcap);
+ roaring_bitmap_set_copy_on_write(answer, is_cow(x1) && is_cow(x2));
+
+ int pos1 = 0, pos2 = 0;
+
+ while (pos1 < length1 && pos2 < length2) {
+ const uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ const uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ if (s1 == s2) {
+ uint8_t container_type_1, container_type_2;
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c = container_and(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ } else {
+ container_free(
+ c, container_result_type); // otherwise:memory leak!
+ }
+ ++pos1;
+ ++pos2;
+ } else if (s1 < s2) { // s1 < s2
+ pos1 = ra_advance_until(&x1->high_low_container, s2, pos1);
+ } else { // s1 > s2
+ pos2 = ra_advance_until(&x2->high_low_container, s1, pos2);
+ }
+ }
+ return answer;
+}
+
+/**
+ * Compute the union of 'number' bitmaps.
+ */
+roaring_bitmap_t *roaring_bitmap_or_many(size_t number,
+ const roaring_bitmap_t **x) {
+ if (number == 0) {
+ return roaring_bitmap_create();
+ }
+ if (number == 1) {
+ return roaring_bitmap_copy(x[0]);
+ }
+ roaring_bitmap_t *answer =
+ roaring_bitmap_lazy_or(x[0], x[1], LAZY_OR_BITSET_CONVERSION);
+ for (size_t i = 2; i < number; i++) {
+ roaring_bitmap_lazy_or_inplace(answer, x[i], LAZY_OR_BITSET_CONVERSION);
+ }
+ roaring_bitmap_repair_after_lazy(answer);
+ return answer;
+}
+
+/**
+ * Compute the xor of 'number' bitmaps.
+ */
+roaring_bitmap_t *roaring_bitmap_xor_many(size_t number,
+ const roaring_bitmap_t **x) {
+ if (number == 0) {
+ return roaring_bitmap_create();
+ }
+ if (number == 1) {
+ return roaring_bitmap_copy(x[0]);
+ }
+ roaring_bitmap_t *answer = roaring_bitmap_lazy_xor(x[0], x[1]);
+ for (size_t i = 2; i < number; i++) {
+ roaring_bitmap_lazy_xor_inplace(answer, x[i]);
+ }
+ roaring_bitmap_repair_after_lazy(answer);
+ return answer;
+}
+
+// inplace and (modifies its first argument).
+void roaring_bitmap_and_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ if (x1 == x2) return;
+ int pos1 = 0, pos2 = 0, intersection_size = 0;
+ const int length1 = ra_get_size(&x1->high_low_container);
+ const int length2 = ra_get_size(&x2->high_low_container);
+
+ // any skipped-over or newly emptied containers in x1
+ // have to be freed.
+ while (pos1 < length1 && pos2 < length2) {
+ const uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ const uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ if (s1 == s2) {
+ uint8_t typecode1, typecode2, typecode_result;
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &typecode1);
+ c1 = get_writable_copy_if_shared(c1, &typecode1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &typecode2);
+ void *c =
+ container_iand(c1, typecode1, c2, typecode2, &typecode_result);
+ if (c != c1) { // in this instance a new container was created, and
+ // we need to free the old one
+ container_free(c1, typecode1);
+ }
+ if (container_nonzero_cardinality(c, typecode_result)) {
+ ra_replace_key_and_container_at_index(&x1->high_low_container,
+ intersection_size, s1, c,
+ typecode_result);
+ intersection_size++;
+ } else {
+ container_free(c, typecode_result);
+ }
+ ++pos1;
+ ++pos2;
+ } else if (s1 < s2) {
+ pos1 = ra_advance_until_freeing(&x1->high_low_container, s2, pos1);
+ } else { // s1 > s2
+ pos2 = ra_advance_until(&x2->high_low_container, s1, pos2);
+ }
+ }
+
+ // if we ended early because x2 ran out, then all remaining in x1 should be
+ // freed
+ while (pos1 < length1) {
+ container_free(x1->high_low_container.containers[pos1],
+ x1->high_low_container.typecodes[pos1]);
+ ++pos1;
+ }
+
+ // all containers after this have either been copied or freed
+ ra_downsize(&x1->high_low_container, intersection_size);
+}
+
+roaring_bitmap_t *roaring_bitmap_or(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ if (0 == length1) {
+ return roaring_bitmap_copy(x2);
+ }
+ if (0 == length2) {
+ return roaring_bitmap_copy(x1);
+ }
+ roaring_bitmap_t *answer =
+ roaring_bitmap_create_with_capacity(length1 + length2);
+ roaring_bitmap_set_copy_on_write(answer, is_cow(x1) && is_cow(x2));
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c = container_or(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+ // since we assume that the initial containers are non-empty, the
+ // result here
+ // can only be non-empty
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ // c1 = container_clone(c1, container_type_1);
+ c1 =
+ get_copy_of_container(c1, &container_type_1, is_cow(x1));
+ if (is_cow(x1)) {
+ ra_set_container_at_index(&x1->high_low_container, pos1, c1,
+ container_type_1);
+ }
+ ra_append(&answer->high_low_container, s1, c1, container_type_1);
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ // c2 = container_clone(c2, container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+ ra_append(&answer->high_low_container, s2, c2, container_type_2);
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x2->high_low_container, pos2, length2,
+ is_cow(x2));
+ } else if (pos2 == length2) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, length1,
+ is_cow(x1));
+ }
+ return answer;
+}
+
+// inplace or (modifies its first argument).
+void roaring_bitmap_or_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ int length1 = x1->high_low_container.size;
+ const int length2 = x2->high_low_container.size;
+
+ if (0 == length2) return;
+
+ if (0 == length1) {
+ roaring_bitmap_overwrite(x1, x2);
+ return;
+ }
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ if (!container_is_full(c1, container_type_1)) {
+ c1 = get_writable_copy_if_shared(c1, &container_type_1);
+
+ void *c2 = ra_get_container_at_index(&x2->high_low_container,
+ pos2, &container_type_2);
+ void *c =
+ container_ior(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+ if (c !=
+ c1) { // in this instance a new container was created, and
+ // we need to free the old one
+ container_free(c1, container_type_1);
+ }
+
+ ra_set_container_at_index(&x1->high_low_container, pos1, c,
+ container_result_type);
+ }
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+
+ // void *c2_clone = container_clone(c2, container_type_2);
+ ra_insert_new_key_value_at(&x1->high_low_container, pos1, s2, c2,
+ container_type_2);
+ pos1++;
+ length1++;
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&x1->high_low_container, &x2->high_low_container,
+ pos2, length2, is_cow(x2));
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_xor(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ if (0 == length1) {
+ return roaring_bitmap_copy(x2);
+ }
+ if (0 == length2) {
+ return roaring_bitmap_copy(x1);
+ }
+ roaring_bitmap_t *answer =
+ roaring_bitmap_create_with_capacity(length1 + length2);
+ roaring_bitmap_set_copy_on_write(answer, is_cow(x1) && is_cow(x2));
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c = container_xor(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ } else {
+ container_free(c, container_result_type);
+ }
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ c1 =
+ get_copy_of_container(c1, &container_type_1, is_cow(x1));
+ if (is_cow(x1)) {
+ ra_set_container_at_index(&x1->high_low_container, pos1, c1,
+ container_type_1);
+ }
+ ra_append(&answer->high_low_container, s1, c1, container_type_1);
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+ ra_append(&answer->high_low_container, s2, c2, container_type_2);
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x2->high_low_container, pos2, length2,
+ is_cow(x2));
+ } else if (pos2 == length2) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, length1,
+ is_cow(x1));
+ }
+ return answer;
+}
+
+// inplace xor (modifies its first argument).
+
+void roaring_bitmap_xor_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ assert(x1 != x2);
+ uint8_t container_result_type = 0;
+ int length1 = x1->high_low_container.size;
+ const int length2 = x2->high_low_container.size;
+
+ if (0 == length2) return;
+
+ if (0 == length1) {
+ roaring_bitmap_overwrite(x1, x2);
+ return;
+ }
+
+ // XOR can have new containers inserted from x2, but can also
+ // lose containers when x1 and x2 are nonempty and identical.
+
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ c1 = get_writable_copy_if_shared(c1, &container_type_1);
+
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c = container_ixor(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_set_container_at_index(&x1->high_low_container, pos1, c,
+ container_result_type);
+ ++pos1;
+ } else {
+ container_free(c, container_result_type);
+ ra_remove_at_index(&x1->high_low_container, pos1);
+ --length1;
+ }
+
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+
+ ra_insert_new_key_value_at(&x1->high_low_container, pos1, s2, c2,
+ container_type_2);
+ pos1++;
+ length1++;
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&x1->high_low_container, &x2->high_low_container,
+ pos2, length2, is_cow(x2));
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_andnot(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ if (0 == length1) {
+ roaring_bitmap_t *empty_bitmap = roaring_bitmap_create();
+ roaring_bitmap_set_copy_on_write(empty_bitmap, is_cow(x1) && is_cow(x2));
+ return empty_bitmap;
+ }
+ if (0 == length2) {
+ return roaring_bitmap_copy(x1);
+ }
+ roaring_bitmap_t *answer = roaring_bitmap_create_with_capacity(length1);
+ roaring_bitmap_set_copy_on_write(answer, is_cow(x1) && is_cow(x2));
+
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = 0;
+ uint16_t s2 = 0;
+ while (true) {
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c =
+ container_andnot(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ } else {
+ container_free(c, container_result_type);
+ }
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ } else if (s1 < s2) { // s1 < s2
+ const int next_pos1 =
+ ra_advance_until(&x1->high_low_container, s2, pos1);
+ ra_append_copy_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, next_pos1,
+ is_cow(x1));
+ // TODO : perhaps some of the copy_on_write should be based on
+ // answer rather than x1 (more stringent?). Many similar cases
+ pos1 = next_pos1;
+ if (pos1 == length1) break;
+ } else { // s1 > s2
+ pos2 = ra_advance_until(&x2->high_low_container, s1, pos2);
+ if (pos2 == length2) break;
+ }
+ }
+ if (pos2 == length2) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, length1,
+ is_cow(x1));
+ }
+ return answer;
+}
+
+// inplace andnot (modifies its first argument).
+
+void roaring_bitmap_andnot_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ assert(x1 != x2);
+
+ uint8_t container_result_type = 0;
+ int length1 = x1->high_low_container.size;
+ const int length2 = x2->high_low_container.size;
+ int intersection_size = 0;
+
+ if (0 == length2) return;
+
+ if (0 == length1) {
+ roaring_bitmap_clear(x1);
+ return;
+ }
+
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ c1 = get_writable_copy_if_shared(c1, &container_type_1);
+
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c =
+ container_iandnot(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_replace_key_and_container_at_index(&x1->high_low_container,
+ intersection_size++, s1,
+ c, container_result_type);
+ } else {
+ container_free(c, container_result_type);
+ }
+
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ if (pos1 != intersection_size) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container,
+ pos1, &container_type_1);
+
+ ra_replace_key_and_container_at_index(&x1->high_low_container,
+ intersection_size, s1, c1,
+ container_type_1);
+ }
+ intersection_size++;
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ pos2 = ra_advance_until(&x2->high_low_container, s1, pos2);
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+
+ if (pos1 < length1) {
+ // all containers between intersection_size and
+ // pos1 are junk. However, they have either been moved
+ // (thus still referenced) or involved in an iandnot
+ // that will clean up all containers that could not be reused.
+ // Thus we should not free the junk containers between
+ // intersection_size and pos1.
+ if (pos1 > intersection_size) {
+ // left slide of remaining items
+ ra_copy_range(&x1->high_low_container, pos1, length1,
+ intersection_size);
+ }
+ // else current placement is fine
+ intersection_size += (length1 - pos1);
+ }
+ ra_downsize(&x1->high_low_container, intersection_size);
+}
+
+uint64_t roaring_bitmap_get_cardinality(const roaring_bitmap_t *ra) {
+ uint64_t card = 0;
+ for (int i = 0; i < ra->high_low_container.size; ++i)
+ card += container_get_cardinality(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]);
+ return card;
+}
+
+uint64_t roaring_bitmap_range_cardinality(const roaring_bitmap_t *ra,
+ uint64_t range_start,
+ uint64_t range_end) {
+ if (range_end > UINT32_MAX) {
+ range_end = UINT32_MAX + UINT64_C(1);
+ }
+ if (range_start >= range_end) {
+ return 0;
+ }
+ range_end--; // make range_end inclusive
+ // now we have: 0 <= range_start <= range_end <= UINT32_MAX
+
+ uint16_t minhb = range_start >> 16;
+ uint16_t maxhb = range_end >> 16;
+
+ uint64_t card = 0;
+
+ int i = ra_get_index(&ra->high_low_container, minhb);
+ if (i >= 0) {
+ if (minhb == maxhb) {
+ card += container_rank(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i],
+ range_end & 0xffff);
+ } else {
+ card += container_get_cardinality(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]);
+ }
+ if ((range_start & 0xffff) != 0) {
+ card -= container_rank(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i],
+ (range_start & 0xffff) - 1);
+ }
+ i++;
+ } else {
+ i = -i - 1;
+ }
+
+ for (; i < ra->high_low_container.size; i++) {
+ uint16_t key = ra->high_low_container.keys[i];
+ if (key < maxhb) {
+ card += container_get_cardinality(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i]);
+ } else if (key == maxhb) {
+ card += container_rank(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i],
+ range_end & 0xffff);
+ break;
+ } else {
+ break;
+ }
+ }
+
+ return card;
+}
+
+
+bool roaring_bitmap_is_empty(const roaring_bitmap_t *ra) {
+ return ra->high_low_container.size == 0;
+}
+
+void roaring_bitmap_to_uint32_array(const roaring_bitmap_t *ra, uint32_t *ans) {
+ ra_to_uint32_array(&ra->high_low_container, ans);
+}
+
+bool roaring_bitmap_range_uint32_array(const roaring_bitmap_t *ra, size_t offset, size_t limit, uint32_t *ans) {
+ return ra_range_uint32_array(&ra->high_low_container, offset, limit, ans);
+}
+
+/** convert array and bitmap containers to run containers when it is more
+ * efficient;
+ * also convert from run containers when more space efficient. Returns
+ * true if the result has at least one run container.
+*/
+bool roaring_bitmap_run_optimize(roaring_bitmap_t *r) {
+ bool answer = false;
+ for (int i = 0; i < r->high_low_container.size; i++) {
+ uint8_t typecode_original, typecode_after;
+ ra_unshare_container_at_index(
+ &r->high_low_container, i); // TODO: this introduces extra cloning!
+ void *c = ra_get_container_at_index(&r->high_low_container, i,
+ &typecode_original);
+ void *c1 = convert_run_optimize(c, typecode_original, &typecode_after);
+ if (typecode_after == RUN_CONTAINER_TYPE_CODE) answer = true;
+ ra_set_container_at_index(&r->high_low_container, i, c1,
+ typecode_after);
+ }
+ return answer;
+}
+
+size_t roaring_bitmap_shrink_to_fit(roaring_bitmap_t *r) {
+ size_t answer = 0;
+ for (int i = 0; i < r->high_low_container.size; i++) {
+ uint8_t typecode_original;
+ void *c = ra_get_container_at_index(&r->high_low_container, i,
+ &typecode_original);
+ answer += container_shrink_to_fit(c, typecode_original);
+ }
+ answer += ra_shrink_to_fit(&r->high_low_container);
+ return answer;
+}
+
+/**
+ * Remove run-length encoding even when it is more space efficient
+ * return whether a change was applied
+ */
+bool roaring_bitmap_remove_run_compression(roaring_bitmap_t *r) {
+ bool answer = false;
+ for (int i = 0; i < r->high_low_container.size; i++) {
+ uint8_t typecode_original, typecode_after;
+ void *c = ra_get_container_at_index(&r->high_low_container, i,
+ &typecode_original);
+ if (get_container_type(c, typecode_original) ==
+ RUN_CONTAINER_TYPE_CODE) {
+ answer = true;
+ if (typecode_original == SHARED_CONTAINER_TYPE_CODE) {
+ run_container_t *truec =
+ (run_container_t *)((shared_container_t *)c)->container;
+ int32_t card = run_container_cardinality(truec);
+ void *c1 = convert_to_bitset_or_array_container(
+ truec, card, &typecode_after);
+ shared_container_free((shared_container_t *)c);// will free the run container as needed
+ ra_set_container_at_index(&r->high_low_container, i, c1,
+ typecode_after);
+
+ } else {
+ int32_t card = run_container_cardinality((run_container_t *)c);
+ void *c1 = convert_to_bitset_or_array_container(
+ (run_container_t *)c, card, &typecode_after);
+ run_container_free((run_container_t *)c);
+ ra_set_container_at_index(&r->high_low_container, i, c1,
+ typecode_after);
+ }
+ }
+ }
+ return answer;
+}
+
+size_t roaring_bitmap_serialize(const roaring_bitmap_t *ra, char *buf) {
+ size_t portablesize = roaring_bitmap_portable_size_in_bytes(ra);
+ uint64_t cardinality = roaring_bitmap_get_cardinality(ra);
+ uint64_t sizeasarray = cardinality * sizeof(uint32_t) + sizeof(uint32_t);
+ if (portablesize < sizeasarray) {
+ buf[0] = SERIALIZATION_CONTAINER;
+ return roaring_bitmap_portable_serialize(ra, buf + 1) + 1;
+ } else {
+ buf[0] = SERIALIZATION_ARRAY_UINT32;
+ memcpy(buf + 1, &cardinality, sizeof(uint32_t));
+ roaring_bitmap_to_uint32_array(
+ ra, (uint32_t *)(buf + 1 + sizeof(uint32_t)));
+ return 1 + (size_t)sizeasarray;
+ }
+}
+
+size_t roaring_bitmap_size_in_bytes(const roaring_bitmap_t *ra) {
+ size_t portablesize = roaring_bitmap_portable_size_in_bytes(ra);
+ uint64_t sizeasarray = roaring_bitmap_get_cardinality(ra) * sizeof(uint32_t) +
+ sizeof(uint32_t);
+ return portablesize < sizeasarray ? portablesize + 1 : (size_t)sizeasarray + 1;
+}
+
+size_t roaring_bitmap_portable_size_in_bytes(const roaring_bitmap_t *ra) {
+ return ra_portable_size_in_bytes(&ra->high_low_container);
+}
+
+
+roaring_bitmap_t *roaring_bitmap_portable_deserialize_safe(const char *buf, size_t maxbytes) {
+ roaring_bitmap_t *ans =
+ (roaring_bitmap_t *)malloc(sizeof(roaring_bitmap_t));
+ if (ans == NULL) {
+ return NULL;
+ }
+ size_t bytesread;
+ bool is_ok = ra_portable_deserialize(&ans->high_low_container, buf, maxbytes, &bytesread);
+ if(is_ok) assert(bytesread <= maxbytes);
+ roaring_bitmap_set_copy_on_write(ans, false);
+ if (!is_ok) {
+ free(ans);
+ return NULL;
+ }
+ return ans;
+}
+
+roaring_bitmap_t *roaring_bitmap_portable_deserialize(const char *buf) {
+ return roaring_bitmap_portable_deserialize_safe(buf, SIZE_MAX);
+}
+
+
+size_t roaring_bitmap_portable_deserialize_size(const char *buf, size_t maxbytes) {
+ return ra_portable_deserialize_size(buf, maxbytes);
+}
+
+
+size_t roaring_bitmap_portable_serialize(const roaring_bitmap_t *ra,
+ char *buf) {
+ return ra_portable_serialize(&ra->high_low_container, buf);
+}
+
+roaring_bitmap_t *roaring_bitmap_deserialize(const void *buf) {
+ const char *bufaschar = (const char *)buf;
+ if (*(const unsigned char *)buf == SERIALIZATION_ARRAY_UINT32) {
+ /* This looks like a compressed set of uint32_t elements */
+ uint32_t card;
+ memcpy(&card, bufaschar + 1, sizeof(uint32_t));
+ const uint32_t *elems =
+ (const uint32_t *)(bufaschar + 1 + sizeof(uint32_t));
+
+ return roaring_bitmap_of_ptr(card, elems);
+ } else if (bufaschar[0] == SERIALIZATION_CONTAINER) {
+ return roaring_bitmap_portable_deserialize(bufaschar + 1);
+ } else
+ return (NULL);
+}
+
+bool roaring_iterate(const roaring_bitmap_t *ra, roaring_iterator iterator,
+ void *ptr) {
+ for (int i = 0; i < ra->high_low_container.size; ++i)
+ if (!container_iterate(ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i],
+ ((uint32_t)ra->high_low_container.keys[i]) << 16,
+ iterator, ptr)) {
+ return false;
+ }
+ return true;
+}
+
+bool roaring_iterate64(const roaring_bitmap_t *ra, roaring_iterator64 iterator,
+ uint64_t high_bits, void *ptr) {
+ for (int i = 0; i < ra->high_low_container.size; ++i)
+ if (!container_iterate64(
+ ra->high_low_container.containers[i],
+ ra->high_low_container.typecodes[i],
+ ((uint32_t)ra->high_low_container.keys[i]) << 16, iterator,
+ high_bits, ptr)) {
+ return false;
+ }
+ return true;
+}
+
+/****
+* begin roaring_uint32_iterator_t
+*****/
+
+// Partially initializes the roaring iterator when it begins looking at
+// a new container.
+static bool iter_new_container_partial_init(roaring_uint32_iterator_t *newit) {
+ newit->in_container_index = 0;
+ newit->run_index = 0;
+ newit->current_value = 0;
+ if (newit->container_index >= newit->parent->high_low_container.size ||
+ newit->container_index < 0) {
+ newit->current_value = UINT32_MAX;
+ return (newit->has_value = false);
+ }
+ // assume not empty
+ newit->has_value = true;
+ // we precompute container, typecode and highbits so that successive
+ // iterators do not have to grab them from odd memory locations
+ // and have to worry about the (easily predicted) container_unwrap_shared
+ // call.
+ newit->container =
+ newit->parent->high_low_container.containers[newit->container_index];
+ newit->typecode =
+ newit->parent->high_low_container.typecodes[newit->container_index];
+ newit->highbits =
+ ((uint32_t)
+ newit->parent->high_low_container.keys[newit->container_index])
+ << 16;
+ newit->container =
+ container_unwrap_shared(newit->container, &(newit->typecode));
+ return newit->has_value;
+}
+
+static bool loadfirstvalue(roaring_uint32_iterator_t *newit) {
+ if (!iter_new_container_partial_init(newit))
+ return newit->has_value;
+
+ uint32_t wordindex;
+ uint64_t word; // used for bitsets
+ switch (newit->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ wordindex = 0;
+ while ((word = ((const bitset_container_t *)(newit->container))
+ ->array[wordindex]) == 0)
+ wordindex++; // advance
+ // here "word" is non-zero
+ newit->in_container_index = wordindex * 64 + __builtin_ctzll(word);
+ newit->current_value = newit->highbits | newit->in_container_index;
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ newit->current_value =
+ newit->highbits |
+ ((const array_container_t *)(newit->container))->array[0];
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ newit->current_value =
+ newit->highbits |
+ (((const run_container_t *)(newit->container))->runs[0].value);
+ break;
+ default:
+ // if this ever happens, bug!
+ assert(false);
+ } // switch (typecode)
+ return true;
+}
+
+static bool loadlastvalue(roaring_uint32_iterator_t* newit) {
+ if (!iter_new_container_partial_init(newit))
+ return newit->has_value;
+
+ switch(newit->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ uint32_t wordindex = BITSET_CONTAINER_SIZE_IN_WORDS - 1;
+ uint64_t word;
+ const bitset_container_t* bitset_container = (const bitset_container_t*)newit->container;
+ while ((word = bitset_container->array[wordindex]) == 0)
+ --wordindex;
+
+ int num_leading_zeros = __builtin_clzll(word);
+ newit->in_container_index = (wordindex * 64) + (63 - num_leading_zeros);
+ newit->current_value = newit->highbits | newit->in_container_index;
+ break;
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ const array_container_t* array_container = (const array_container_t*)newit->container;
+ newit->in_container_index = array_container->cardinality - 1;
+ newit->current_value = newit->highbits | array_container->array[newit->in_container_index];
+ break;
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ const run_container_t* run_container = (const run_container_t*)newit->container;
+ newit->run_index = run_container->n_runs - 1;
+ const rle16_t* last_run = &run_container->runs[newit->run_index];
+ newit->current_value = newit->highbits | (last_run->value + last_run->length);
+ break;
+ }
+ default:
+ // if this ever happens, bug!
+ assert(false);
+ }
+ return true;
+}
+
+// prerequesite: the value should be in range of the container
+static bool loadfirstvalue_largeorequal(roaring_uint32_iterator_t *newit, uint32_t val) {
+ // Don't have to check return value because of prerequisite
+ iter_new_container_partial_init(newit);
+ uint16_t lb = val & 0xFFFF;
+
+ switch (newit->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ newit->in_container_index = bitset_container_index_equalorlarger((const bitset_container_t *)(newit->container), lb);
+ newit->current_value = newit->highbits | newit->in_container_index;
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ newit->in_container_index = array_container_index_equalorlarger((const array_container_t *)(newit->container), lb);
+ newit->current_value =
+ newit->highbits |
+ ((const array_container_t *)(newit->container))->array[newit->in_container_index];
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ newit->run_index = run_container_index_equalorlarger((const run_container_t *)(newit->container), lb);
+ if(((const run_container_t *)(newit->container))->runs[newit->run_index].value <= lb) {
+ newit->current_value = val;
+ } else {
+ newit->current_value =
+ newit->highbits |
+ (((const run_container_t *)(newit->container))->runs[newit->run_index].value);
+ }
+ break;
+ default:
+ // if this ever happens, bug!
+ assert(false);
+ } // switch (typecode)
+ return true;
+}
+
+void roaring_init_iterator(const roaring_bitmap_t *ra,
+ roaring_uint32_iterator_t *newit) {
+ newit->parent = ra;
+ newit->container_index = 0;
+ newit->has_value = loadfirstvalue(newit);
+}
+
+void roaring_init_iterator_last(const roaring_bitmap_t *ra,
+ roaring_uint32_iterator_t *newit) {
+ newit->parent = ra;
+ newit->container_index = newit->parent->high_low_container.size - 1;
+ newit->has_value = loadlastvalue(newit);
+}
+
+roaring_uint32_iterator_t *roaring_create_iterator(const roaring_bitmap_t *ra) {
+ roaring_uint32_iterator_t *newit =
+ (roaring_uint32_iterator_t *)malloc(sizeof(roaring_uint32_iterator_t));
+ if (newit == NULL) return NULL;
+ roaring_init_iterator(ra, newit);
+ return newit;
+}
+
+roaring_uint32_iterator_t *roaring_copy_uint32_iterator(
+ const roaring_uint32_iterator_t *it) {
+ roaring_uint32_iterator_t *newit =
+ (roaring_uint32_iterator_t *)malloc(sizeof(roaring_uint32_iterator_t));
+ memcpy(newit, it, sizeof(roaring_uint32_iterator_t));
+ return newit;
+}
+
+bool roaring_move_uint32_iterator_equalorlarger(roaring_uint32_iterator_t *it, uint32_t val) {
+ uint16_t hb = val >> 16;
+ const int i = ra_get_index(& it->parent->high_low_container, hb);
+ if (i >= 0) {
+ uint32_t lowvalue = container_maximum(it->parent->high_low_container.containers[i], it->parent->high_low_container.typecodes[i]);
+ uint16_t lb = val & 0xFFFF;
+ if(lowvalue < lb ) {
+ it->container_index = i+1; // will have to load first value of next container
+ } else {// the value is necessarily within the range of the container
+ it->container_index = i;
+ it->has_value = loadfirstvalue_largeorequal(it, val);
+ return it->has_value;
+ }
+ } else {
+ // there is no matching, so we are going for the next container
+ it->container_index = -i-1;
+ }
+ it->has_value = loadfirstvalue(it);
+ return it->has_value;
+}
+
+
+bool roaring_advance_uint32_iterator(roaring_uint32_iterator_t *it) {
+ if (it->container_index >= it->parent->high_low_container.size) {
+ return (it->has_value = false);
+ }
+ if (it->container_index < 0) {
+ it->container_index = 0;
+ return (it->has_value = loadfirstvalue(it));
+ }
+
+ uint32_t wordindex; // used for bitsets
+ uint64_t word; // used for bitsets
+ switch (it->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ it->in_container_index++;
+ wordindex = it->in_container_index / 64;
+ if (wordindex >= BITSET_CONTAINER_SIZE_IN_WORDS) break;
+ word = ((const bitset_container_t *)(it->container))
+ ->array[wordindex] &
+ (UINT64_MAX << (it->in_container_index % 64));
+ // next part could be optimized/simplified
+ while ((word == 0) &&
+ (wordindex + 1 < BITSET_CONTAINER_SIZE_IN_WORDS)) {
+ wordindex++;
+ word = ((const bitset_container_t *)(it->container))
+ ->array[wordindex];
+ }
+ if (word != 0) {
+ it->in_container_index = wordindex * 64 + __builtin_ctzll(word);
+ it->current_value = it->highbits | it->in_container_index;
+ return (it->has_value = true);
+ }
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ it->in_container_index++;
+ if (it->in_container_index <
+ ((const array_container_t *)(it->container))->cardinality) {
+ it->current_value = it->highbits |
+ ((const array_container_t *)(it->container))
+ ->array[it->in_container_index];
+ return (it->has_value = true);
+ }
+ break;
+ case RUN_CONTAINER_TYPE_CODE: {
+ if(it->current_value == UINT32_MAX) {
+ return (it->has_value = false); // without this, we risk an overflow to zero
+ }
+
+ const run_container_t* run_container = (const run_container_t*)it->container;
+ if (++it->current_value <= (it->highbits | (run_container->runs[it->run_index].value +
+ run_container->runs[it->run_index].length))) {
+ return (it->has_value = true);
+ }
+
+ if (++it->run_index < run_container->n_runs) {
+ // Assume the run has a value
+ it->current_value = it->highbits | run_container->runs[it->run_index].value;
+ return (it->has_value = true);
+ }
+ break;
+ }
+ default:
+ // if this ever happens, bug!
+ assert(false);
+ } // switch (typecode)
+ // moving to next container
+ it->container_index++;
+ return (it->has_value = loadfirstvalue(it));
+}
+
+bool roaring_previous_uint32_iterator(roaring_uint32_iterator_t *it) {
+ if (it->container_index < 0) {
+ return (it->has_value = false);
+ }
+ if (it->container_index >= it->parent->high_low_container.size) {
+ it->container_index = it->parent->high_low_container.size - 1;
+ return (it->has_value = loadlastvalue(it));
+ }
+
+ switch (it->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ if (--it->in_container_index < 0)
+ break;
+
+ const bitset_container_t* bitset_container = (const bitset_container_t*)it->container;
+ int32_t wordindex = it->in_container_index / 64;
+ uint64_t word = bitset_container->array[wordindex] & (UINT64_MAX >> (63 - (it->in_container_index % 64)));
+
+ while (word == 0 && --wordindex >= 0) {
+ word = bitset_container->array[wordindex];
+ }
+ if (word == 0)
+ break;
+
+ int num_leading_zeros = __builtin_clzll(word);
+ it->in_container_index = (wordindex * 64) + (63 - num_leading_zeros);
+ it->current_value = it->highbits | it->in_container_index;
+ return (it->has_value = true);
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ if (--it->in_container_index < 0)
+ break;
+
+ const array_container_t* array_container = (const array_container_t*)it->container;
+ it->current_value = it->highbits | array_container->array[it->in_container_index];
+ return (it->has_value = true);
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ if(it->current_value == 0)
+ return (it->has_value = false);
+
+ const run_container_t* run_container = (const run_container_t*)it->container;
+ if (--it->current_value >= (it->highbits | run_container->runs[it->run_index].value)) {
+ return (it->has_value = true);
+ }
+
+ if (--it->run_index < 0)
+ break;
+
+ it->current_value = it->highbits | (run_container->runs[it->run_index].value +
+ run_container->runs[it->run_index].length);
+ return (it->has_value = true);
+ }
+ default:
+ // if this ever happens, bug!
+ assert(false);
+ } // switch (typecode)
+
+ // moving to previous container
+ it->container_index--;
+ return (it->has_value = loadlastvalue(it));
+}
+
+uint32_t roaring_read_uint32_iterator(roaring_uint32_iterator_t *it, uint32_t* buf, uint32_t count) {
+ uint32_t ret = 0;
+ uint32_t num_values;
+ uint32_t wordindex; // used for bitsets
+ uint64_t word; // used for bitsets
+ const array_container_t* acont; //TODO remove
+ const run_container_t* rcont; //TODO remove
+ const bitset_container_t* bcont; //TODO remove
+
+ while (it->has_value && ret < count) {
+ switch (it->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ bcont = (const bitset_container_t*)(it->container);
+ wordindex = it->in_container_index / 64;
+ word = bcont->array[wordindex] & (UINT64_MAX << (it->in_container_index % 64));
+ do {
+ while (word != 0 && ret < count) {
+ buf[0] = it->highbits | (wordindex * 64 + __builtin_ctzll(word));
+ word = word & (word - 1);
+ buf++;
+ ret++;
+ }
+ while (word == 0 && wordindex+1 < BITSET_CONTAINER_SIZE_IN_WORDS) {
+ wordindex++;
+ word = bcont->array[wordindex];
+ }
+ } while (word != 0 && ret < count);
+ it->has_value = (word != 0);
+ if (it->has_value) {
+ it->in_container_index = wordindex * 64 + __builtin_ctzll(word);
+ it->current_value = it->highbits | it->in_container_index;
+ }
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ acont = (const array_container_t *)(it->container);
+ num_values = minimum_uint32(acont->cardinality - it->in_container_index, count - ret);
+ for (uint32_t i = 0; i < num_values; i++) {
+ buf[i] = it->highbits | acont->array[it->in_container_index + i];
+ }
+ buf += num_values;
+ ret += num_values;
+ it->in_container_index += num_values;
+ it->has_value = (it->in_container_index < acont->cardinality);
+ if (it->has_value) {
+ it->current_value = it->highbits | acont->array[it->in_container_index];
+ }
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ rcont = (const run_container_t*)(it->container);
+ //"in_run_index" name is misleading, read it as "max_value_in_current_run"
+ do {
+ uint32_t largest_run_value = it->highbits | (rcont->runs[it->run_index].value + rcont->runs[it->run_index].length);
+ num_values = minimum_uint32(largest_run_value - it->current_value + 1, count - ret);
+ for (uint32_t i = 0; i < num_values; i++) {
+ buf[i] = it->current_value + i;
+ }
+ it->current_value += num_values; // this can overflow to zero: UINT32_MAX+1=0
+ buf += num_values;
+ ret += num_values;
+
+ if (it->current_value > largest_run_value || it->current_value == 0) {
+ it->run_index++;
+ if (it->run_index < rcont->n_runs) {
+ it->current_value = it->highbits | rcont->runs[it->run_index].value;
+ } else {
+ it->has_value = false;
+ }
+ }
+ } while ((ret < count) && it->has_value);
+ break;
+ default:
+ assert(false);
+ }
+ if (it->has_value) {
+ assert(ret == count);
+ return ret;
+ }
+ it->container_index++;
+ it->has_value = loadfirstvalue(it);
+ }
+ return ret;
+}
+
+
+
+void roaring_free_uint32_iterator(roaring_uint32_iterator_t *it) { free(it); }
+
+/****
+* end of roaring_uint32_iterator_t
+*****/
+
+bool roaring_bitmap_equals(const roaring_bitmap_t *ra1,
+ const roaring_bitmap_t *ra2) {
+ if (ra1->high_low_container.size != ra2->high_low_container.size) {
+ return false;
+ }
+ for (int i = 0; i < ra1->high_low_container.size; ++i) {
+ if (ra1->high_low_container.keys[i] !=
+ ra2->high_low_container.keys[i]) {
+ return false;
+ }
+ }
+ for (int i = 0; i < ra1->high_low_container.size; ++i) {
+ bool areequal = container_equals(ra1->high_low_container.containers[i],
+ ra1->high_low_container.typecodes[i],
+ ra2->high_low_container.containers[i],
+ ra2->high_low_container.typecodes[i]);
+ if (!areequal) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool roaring_bitmap_is_subset(const roaring_bitmap_t *ra1,
+ const roaring_bitmap_t *ra2) {
+ const int length1 = ra1->high_low_container.size,
+ length2 = ra2->high_low_container.size;
+
+ int pos1 = 0, pos2 = 0;
+
+ while (pos1 < length1 && pos2 < length2) {
+ const uint16_t s1 = ra_get_key_at_index(&ra1->high_low_container, pos1);
+ const uint16_t s2 = ra_get_key_at_index(&ra2->high_low_container, pos2);
+
+ if (s1 == s2) {
+ uint8_t container_type_1, container_type_2;
+ void *c1 = ra_get_container_at_index(&ra1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&ra2->high_low_container, pos2,
+ &container_type_2);
+ bool subset =
+ container_is_subset(c1, container_type_1, c2, container_type_2);
+ if (!subset) return false;
+ ++pos1;
+ ++pos2;
+ } else if (s1 < s2) { // s1 < s2
+ return false;
+ } else { // s1 > s2
+ pos2 = ra_advance_until(&ra2->high_low_container, s1, pos2);
+ }
+ }
+ if (pos1 == length1)
+ return true;
+ else
+ return false;
+}
+
+static void insert_flipped_container(roaring_array_t *ans_arr,
+ const roaring_array_t *x1_arr, uint16_t hb,
+ uint16_t lb_start, uint16_t lb_end) {
+ const int i = ra_get_index(x1_arr, hb);
+ const int j = ra_get_index(ans_arr, hb);
+ uint8_t ctype_in, ctype_out;
+ void *flipped_container = NULL;
+ if (i >= 0) {
+ void *container_to_flip =
+ ra_get_container_at_index(x1_arr, i, &ctype_in);
+ flipped_container =
+ container_not_range(container_to_flip, ctype_in, (uint32_t)lb_start,
+ (uint32_t)(lb_end + 1), &ctype_out);
+
+ if (container_get_cardinality(flipped_container, ctype_out))
+ ra_insert_new_key_value_at(ans_arr, -j - 1, hb, flipped_container,
+ ctype_out);
+ else {
+ container_free(flipped_container, ctype_out);
+ }
+ } else {
+ flipped_container = container_range_of_ones(
+ (uint32_t)lb_start, (uint32_t)(lb_end + 1), &ctype_out);
+ ra_insert_new_key_value_at(ans_arr, -j - 1, hb, flipped_container,
+ ctype_out);
+ }
+}
+
+static void inplace_flip_container(roaring_array_t *x1_arr, uint16_t hb,
+ uint16_t lb_start, uint16_t lb_end) {
+ const int i = ra_get_index(x1_arr, hb);
+ uint8_t ctype_in, ctype_out;
+ void *flipped_container = NULL;
+ if (i >= 0) {
+ void *container_to_flip =
+ ra_get_container_at_index(x1_arr, i, &ctype_in);
+ flipped_container = container_inot_range(
+ container_to_flip, ctype_in, (uint32_t)lb_start,
+ (uint32_t)(lb_end + 1), &ctype_out);
+ // if a new container was created, the old one was already freed
+ if (container_get_cardinality(flipped_container, ctype_out)) {
+ ra_set_container_at_index(x1_arr, i, flipped_container, ctype_out);
+ } else {
+ container_free(flipped_container, ctype_out);
+ ra_remove_at_index(x1_arr, i);
+ }
+
+ } else {
+ flipped_container = container_range_of_ones(
+ (uint32_t)lb_start, (uint32_t)(lb_end + 1), &ctype_out);
+ ra_insert_new_key_value_at(x1_arr, -i - 1, hb, flipped_container,
+ ctype_out);
+ }
+}
+
+static void insert_fully_flipped_container(roaring_array_t *ans_arr,
+ const roaring_array_t *x1_arr,
+ uint16_t hb) {
+ const int i = ra_get_index(x1_arr, hb);
+ const int j = ra_get_index(ans_arr, hb);
+ uint8_t ctype_in, ctype_out;
+ void *flipped_container = NULL;
+ if (i >= 0) {
+ void *container_to_flip =
+ ra_get_container_at_index(x1_arr, i, &ctype_in);
+ flipped_container =
+ container_not(container_to_flip, ctype_in, &ctype_out);
+ if (container_get_cardinality(flipped_container, ctype_out))
+ ra_insert_new_key_value_at(ans_arr, -j - 1, hb, flipped_container,
+ ctype_out);
+ else {
+ container_free(flipped_container, ctype_out);
+ }
+ } else {
+ flipped_container = container_range_of_ones(0U, 0x10000U, &ctype_out);
+ ra_insert_new_key_value_at(ans_arr, -j - 1, hb, flipped_container,
+ ctype_out);
+ }
+}
+
+static void inplace_fully_flip_container(roaring_array_t *x1_arr, uint16_t hb) {
+ const int i = ra_get_index(x1_arr, hb);
+ uint8_t ctype_in, ctype_out;
+ void *flipped_container = NULL;
+ if (i >= 0) {
+ void *container_to_flip =
+ ra_get_container_at_index(x1_arr, i, &ctype_in);
+ flipped_container =
+ container_inot(container_to_flip, ctype_in, &ctype_out);
+
+ if (container_get_cardinality(flipped_container, ctype_out)) {
+ ra_set_container_at_index(x1_arr, i, flipped_container, ctype_out);
+ } else {
+ container_free(flipped_container, ctype_out);
+ ra_remove_at_index(x1_arr, i);
+ }
+
+ } else {
+ flipped_container = container_range_of_ones(0U, 0x10000U, &ctype_out);
+ ra_insert_new_key_value_at(x1_arr, -i - 1, hb, flipped_container,
+ ctype_out);
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *x1,
+ uint64_t range_start,
+ uint64_t range_end) {
+ if (range_start >= range_end) {
+ return roaring_bitmap_copy(x1);
+ }
+ if(range_end >= UINT64_C(0x100000000)) {
+ range_end = UINT64_C(0x100000000);
+ }
+
+ roaring_bitmap_t *ans = roaring_bitmap_create();
+ roaring_bitmap_set_copy_on_write(ans, is_cow(x1));
+
+ uint16_t hb_start = (uint16_t)(range_start >> 16);
+ const uint16_t lb_start = (uint16_t)range_start; // & 0xFFFF;
+ uint16_t hb_end = (uint16_t)((range_end - 1) >> 16);
+ const uint16_t lb_end = (uint16_t)(range_end - 1); // & 0xFFFF;
+
+ ra_append_copies_until(&ans->high_low_container, &x1->high_low_container,
+ hb_start, is_cow(x1));
+ if (hb_start == hb_end) {
+ insert_flipped_container(&ans->high_low_container,
+ &x1->high_low_container, hb_start, lb_start,
+ lb_end);
+ } else {
+ // start and end containers are distinct
+ if (lb_start > 0) {
+ // handle first (partial) container
+ insert_flipped_container(&ans->high_low_container,
+ &x1->high_low_container, hb_start,
+ lb_start, 0xFFFF);
+ ++hb_start; // for the full containers. Can't wrap.
+ }
+
+ if (lb_end != 0xFFFF) --hb_end; // later we'll handle the partial block
+
+ for (uint32_t hb = hb_start; hb <= hb_end; ++hb) {
+ insert_fully_flipped_container(&ans->high_low_container,
+ &x1->high_low_container, hb);
+ }
+
+ // handle a partial final container
+ if (lb_end != 0xFFFF) {
+ insert_flipped_container(&ans->high_low_container,
+ &x1->high_low_container, hb_end + 1, 0,
+ lb_end);
+ ++hb_end;
+ }
+ }
+ ra_append_copies_after(&ans->high_low_container, &x1->high_low_container,
+ hb_end, is_cow(x1));
+ return ans;
+}
+
+void roaring_bitmap_flip_inplace(roaring_bitmap_t *x1, uint64_t range_start,
+ uint64_t range_end) {
+ if (range_start >= range_end) {
+ return; // empty range
+ }
+ if(range_end >= UINT64_C(0x100000000)) {
+ range_end = UINT64_C(0x100000000);
+ }
+
+ uint16_t hb_start = (uint16_t)(range_start >> 16);
+ const uint16_t lb_start = (uint16_t)range_start;
+ uint16_t hb_end = (uint16_t)((range_end - 1) >> 16);
+ const uint16_t lb_end = (uint16_t)(range_end - 1);
+
+ if (hb_start == hb_end) {
+ inplace_flip_container(&x1->high_low_container, hb_start, lb_start,
+ lb_end);
+ } else {
+ // start and end containers are distinct
+ if (lb_start > 0) {
+ // handle first (partial) container
+ inplace_flip_container(&x1->high_low_container, hb_start, lb_start,
+ 0xFFFF);
+ ++hb_start; // for the full containers. Can't wrap.
+ }
+
+ if (lb_end != 0xFFFF) --hb_end;
+
+ for (uint32_t hb = hb_start; hb <= hb_end; ++hb) {
+ inplace_fully_flip_container(&x1->high_low_container, hb);
+ }
+ // handle a partial final container
+ if (lb_end != 0xFFFF) {
+ inplace_flip_container(&x1->high_low_container, hb_end + 1, 0,
+ lb_end);
+ ++hb_end;
+ }
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_lazy_or(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2,
+ const bool bitsetconversion) {
+ uint8_t container_result_type = 0;
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ if (0 == length1) {
+ return roaring_bitmap_copy(x2);
+ }
+ if (0 == length2) {
+ return roaring_bitmap_copy(x1);
+ }
+ roaring_bitmap_t *answer =
+ roaring_bitmap_create_with_capacity(length1 + length2);
+ roaring_bitmap_set_copy_on_write(answer, is_cow(x1) && is_cow(x2));
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c;
+ if (bitsetconversion && (get_container_type(c1, container_type_1) !=
+ BITSET_CONTAINER_TYPE_CODE) &&
+ (get_container_type(c2, container_type_2) !=
+ BITSET_CONTAINER_TYPE_CODE)) {
+ void *newc1 =
+ container_mutable_unwrap_shared(c1, &container_type_1);
+ newc1 = container_to_bitset(newc1, container_type_1);
+ container_type_1 = BITSET_CONTAINER_TYPE_CODE;
+ c = container_lazy_ior(newc1, container_type_1, c2,
+ container_type_2,
+ &container_result_type);
+ if (c != newc1) { // should not happen
+ container_free(newc1, container_type_1);
+ }
+ } else {
+ c = container_lazy_or(c1, container_type_1, c2,
+ container_type_2, &container_result_type);
+ }
+ // since we assume that the initial containers are non-empty,
+ // the
+ // result here
+ // can only be non-empty
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ c1 =
+ get_copy_of_container(c1, &container_type_1, is_cow(x1));
+ if (is_cow(x1)) {
+ ra_set_container_at_index(&x1->high_low_container, pos1, c1,
+ container_type_1);
+ }
+ ra_append(&answer->high_low_container, s1, c1, container_type_1);
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+ ra_append(&answer->high_low_container, s2, c2, container_type_2);
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x2->high_low_container, pos2, length2,
+ is_cow(x2));
+ } else if (pos2 == length2) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, length1,
+ is_cow(x1));
+ }
+ return answer;
+}
+
+void roaring_bitmap_lazy_or_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2,
+ const bool bitsetconversion) {
+ uint8_t container_result_type = 0;
+ int length1 = x1->high_low_container.size;
+ const int length2 = x2->high_low_container.size;
+
+ if (0 == length2) return;
+
+ if (0 == length1) {
+ roaring_bitmap_overwrite(x1, x2);
+ return;
+ }
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ if (!container_is_full(c1, container_type_1)) {
+ if ((bitsetconversion == false) ||
+ (get_container_type(c1, container_type_1) ==
+ BITSET_CONTAINER_TYPE_CODE)) {
+ c1 = get_writable_copy_if_shared(c1, &container_type_1);
+ } else {
+ // convert to bitset
+ void *oldc1 = c1;
+ uint8_t oldt1 = container_type_1;
+ c1 = container_mutable_unwrap_shared(c1, &container_type_1);
+ c1 = container_to_bitset(c1, container_type_1);
+ container_free(oldc1, oldt1);
+ container_type_1 = BITSET_CONTAINER_TYPE_CODE;
+ }
+
+ void *c2 = ra_get_container_at_index(&x2->high_low_container,
+ pos2, &container_type_2);
+ void *c = container_lazy_ior(c1, container_type_1, c2,
+ container_type_2,
+ &container_result_type);
+ if (c !=
+ c1) { // in this instance a new container was created, and
+ // we need to free the old one
+ container_free(c1, container_type_1);
+ }
+
+ ra_set_container_at_index(&x1->high_low_container, pos1, c,
+ container_result_type);
+ }
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ // void *c2_clone = container_clone(c2, container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+ ra_insert_new_key_value_at(&x1->high_low_container, pos1, s2, c2,
+ container_type_2);
+ pos1++;
+ length1++;
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&x1->high_low_container, &x2->high_low_container,
+ pos2, length2, is_cow(x2));
+ }
+}
+
+roaring_bitmap_t *roaring_bitmap_lazy_xor(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ if (0 == length1) {
+ return roaring_bitmap_copy(x2);
+ }
+ if (0 == length2) {
+ return roaring_bitmap_copy(x1);
+ }
+ roaring_bitmap_t *answer =
+ roaring_bitmap_create_with_capacity(length1 + length2);
+ roaring_bitmap_set_copy_on_write(answer, is_cow(x1) && is_cow(x2));
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c =
+ container_lazy_xor(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ } else {
+ container_free(c, container_result_type);
+ }
+
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ c1 =
+ get_copy_of_container(c1, &container_type_1, is_cow(x1));
+ if (is_cow(x1)) {
+ ra_set_container_at_index(&x1->high_low_container, pos1, c1,
+ container_type_1);
+ }
+ ra_append(&answer->high_low_container, s1, c1, container_type_1);
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+ ra_append(&answer->high_low_container, s2, c2, container_type_2);
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x2->high_low_container, pos2, length2,
+ is_cow(x2));
+ } else if (pos2 == length2) {
+ ra_append_copy_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, length1,
+ is_cow(x1));
+ }
+ return answer;
+}
+
+void roaring_bitmap_lazy_xor_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ assert(x1 != x2);
+ uint8_t container_result_type = 0;
+ int length1 = x1->high_low_container.size;
+ const int length2 = x2->high_low_container.size;
+
+ if (0 == length2) return;
+
+ if (0 == length1) {
+ roaring_bitmap_overwrite(x1, x2);
+ return;
+ }
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ c1 = get_writable_copy_if_shared(c1, &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ void *c =
+ container_lazy_ixor(c1, container_type_1, c2, container_type_2,
+ &container_result_type);
+ if (container_nonzero_cardinality(c, container_result_type)) {
+ ra_set_container_at_index(&x1->high_low_container, pos1, c,
+ container_result_type);
+ ++pos1;
+ } else {
+ container_free(c, container_result_type);
+ ra_remove_at_index(&x1->high_low_container, pos1);
+ --length1;
+ }
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ // void *c2_clone = container_clone(c2, container_type_2);
+ c2 =
+ get_copy_of_container(c2, &container_type_2, is_cow(x2));
+ if (is_cow(x2)) {
+ ra_set_container_at_index(&x2->high_low_container, pos2, c2,
+ container_type_2);
+ }
+ ra_insert_new_key_value_at(&x1->high_low_container, pos1, s2, c2,
+ container_type_2);
+ pos1++;
+ length1++;
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_copy_range(&x1->high_low_container, &x2->high_low_container,
+ pos2, length2, is_cow(x2));
+ }
+}
+
+void roaring_bitmap_repair_after_lazy(roaring_bitmap_t *ra) {
+ for (int i = 0; i < ra->high_low_container.size; ++i) {
+ const uint8_t original_typecode = ra->high_low_container.typecodes[i];
+ void *container = ra->high_low_container.containers[i];
+ uint8_t new_typecode = original_typecode;
+ void *newcontainer =
+ container_repair_after_lazy(container, &new_typecode);
+ ra->high_low_container.containers[i] = newcontainer;
+ ra->high_low_container.typecodes[i] = new_typecode;
+ }
+}
+
+
+
+/**
+* roaring_bitmap_rank returns the number of integers that are smaller or equal
+* to x.
+*/
+uint64_t roaring_bitmap_rank(const roaring_bitmap_t *bm, uint32_t x) {
+ uint64_t size = 0;
+ uint32_t xhigh = x >> 16;
+ for (int i = 0; i < bm->high_low_container.size; i++) {
+ uint32_t key = bm->high_low_container.keys[i];
+ if (xhigh > key) {
+ size +=
+ container_get_cardinality(bm->high_low_container.containers[i],
+ bm->high_low_container.typecodes[i]);
+ } else if (xhigh == key) {
+ return size + container_rank(bm->high_low_container.containers[i],
+ bm->high_low_container.typecodes[i],
+ x & 0xFFFF);
+ } else {
+ return size;
+ }
+ }
+ return size;
+}
+
+/**
+* roaring_bitmap_smallest returns the smallest value in the set.
+* Returns UINT32_MAX if the set is empty.
+*/
+uint32_t roaring_bitmap_minimum(const roaring_bitmap_t *bm) {
+ if (bm->high_low_container.size > 0) {
+ void *container = bm->high_low_container.containers[0];
+ uint8_t typecode = bm->high_low_container.typecodes[0];
+ uint32_t key = bm->high_low_container.keys[0];
+ uint32_t lowvalue = container_minimum(container, typecode);
+ return lowvalue | (key << 16);
+ }
+ return UINT32_MAX;
+}
+
+/**
+* roaring_bitmap_smallest returns the greatest value in the set.
+* Returns 0 if the set is empty.
+*/
+uint32_t roaring_bitmap_maximum(const roaring_bitmap_t *bm) {
+ if (bm->high_low_container.size > 0) {
+ void *container =
+ bm->high_low_container.containers[bm->high_low_container.size - 1];
+ uint8_t typecode =
+ bm->high_low_container.typecodes[bm->high_low_container.size - 1];
+ uint32_t key =
+ bm->high_low_container.keys[bm->high_low_container.size - 1];
+ uint32_t lowvalue = container_maximum(container, typecode);
+ return lowvalue | (key << 16);
+ }
+ return 0;
+}
+
+bool roaring_bitmap_select(const roaring_bitmap_t *bm, uint32_t rank,
+ uint32_t *element) {
+ void *container;
+ uint8_t typecode;
+ uint16_t key;
+ uint32_t start_rank = 0;
+ int i = 0;
+ bool valid = false;
+ while (!valid && i < bm->high_low_container.size) {
+ container = bm->high_low_container.containers[i];
+ typecode = bm->high_low_container.typecodes[i];
+ valid =
+ container_select(container, typecode, &start_rank, rank, element);
+ i++;
+ }
+
+ if (valid) {
+ key = bm->high_low_container.keys[i - 1];
+ *element |= (key << 16);
+ return true;
+ } else
+ return false;
+}
+
+bool roaring_bitmap_intersect(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ uint64_t answer = 0;
+ int pos1 = 0, pos2 = 0;
+
+ while (pos1 < length1 && pos2 < length2) {
+ const uint16_t s1 = ra_get_key_at_index(& x1->high_low_container, pos1);
+ const uint16_t s2 = ra_get_key_at_index(& x2->high_low_container, pos2);
+
+ if (s1 == s2) {
+ uint8_t container_type_1, container_type_2;
+ void *c1 = ra_get_container_at_index(& x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(& x2->high_low_container, pos2,
+ &container_type_2);
+ if( container_intersect(c1, container_type_1, c2, container_type_2) ) return true;
+ ++pos1;
+ ++pos2;
+ } else if (s1 < s2) { // s1 < s2
+ pos1 = ra_advance_until(& x1->high_low_container, s2, pos1);
+ } else { // s1 > s2
+ pos2 = ra_advance_until(& x2->high_low_container, s1, pos2);
+ }
+ }
+ return answer;
+}
+
+
+uint64_t roaring_bitmap_and_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ const int length1 = x1->high_low_container.size,
+ length2 = x2->high_low_container.size;
+ uint64_t answer = 0;
+ int pos1 = 0, pos2 = 0;
+
+ while (pos1 < length1 && pos2 < length2) {
+ const uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ const uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ if (s1 == s2) {
+ uint8_t container_type_1, container_type_2;
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ answer += container_and_cardinality(c1, container_type_1, c2,
+ container_type_2);
+ ++pos1;
+ ++pos2;
+ } else if (s1 < s2) { // s1 < s2
+ pos1 = ra_advance_until(&x1->high_low_container, s2, pos1);
+ } else { // s1 > s2
+ pos2 = ra_advance_until(&x2->high_low_container, s1, pos2);
+ }
+ }
+ return answer;
+}
+
+double roaring_bitmap_jaccard_index(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ const uint64_t c1 = roaring_bitmap_get_cardinality(x1);
+ const uint64_t c2 = roaring_bitmap_get_cardinality(x2);
+ const uint64_t inter = roaring_bitmap_and_cardinality(x1, x2);
+ return (double)inter / (double)(c1 + c2 - inter);
+}
+
+uint64_t roaring_bitmap_or_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ const uint64_t c1 = roaring_bitmap_get_cardinality(x1);
+ const uint64_t c2 = roaring_bitmap_get_cardinality(x2);
+ const uint64_t inter = roaring_bitmap_and_cardinality(x1, x2);
+ return c1 + c2 - inter;
+}
+
+uint64_t roaring_bitmap_andnot_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ const uint64_t c1 = roaring_bitmap_get_cardinality(x1);
+ const uint64_t inter = roaring_bitmap_and_cardinality(x1, x2);
+ return c1 - inter;
+}
+
+uint64_t roaring_bitmap_xor_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2) {
+ const uint64_t c1 = roaring_bitmap_get_cardinality(x1);
+ const uint64_t c2 = roaring_bitmap_get_cardinality(x2);
+ const uint64_t inter = roaring_bitmap_and_cardinality(x1, x2);
+ return c1 + c2 - 2 * inter;
+}
+
+
+/**
+ * Check whether a range of values from range_start (included) to range_end (excluded) is present
+ */
+bool roaring_bitmap_contains_range(const roaring_bitmap_t *r, uint64_t range_start, uint64_t range_end) {
+ if(range_end >= UINT64_C(0x100000000)) {
+ range_end = UINT64_C(0x100000000);
+ }
+ if (range_start >= range_end) return true; // empty range are always contained!
+ if (range_end - range_start == 1) return roaring_bitmap_contains(r, (uint32_t)range_start);
+ uint16_t hb_rs = (uint16_t)(range_start >> 16);
+ uint16_t hb_re = (uint16_t)((range_end - 1) >> 16);
+ const int32_t span = hb_re - hb_rs;
+ const int32_t hlc_sz = ra_get_size(&r->high_low_container);
+ if (hlc_sz < span + 1) {
+ return false;
+ }
+ int32_t is = ra_get_index(&r->high_low_container, hb_rs);
+ int32_t ie = ra_get_index(&r->high_low_container, hb_re);
+ ie = (ie < 0 ? -ie - 1 : ie);
+ if ((is < 0) || ((ie - is) != span)) {
+ return false;
+ }
+ const uint32_t lb_rs = range_start & 0xFFFF;
+ const uint32_t lb_re = ((range_end - 1) & 0xFFFF) + 1;
+ uint8_t typecode;
+ void *container = ra_get_container_at_index(&r->high_low_container, is, &typecode);
+ if (hb_rs == hb_re) {
+ return container_contains_range(container, lb_rs, lb_re, typecode);
+ }
+ if (!container_contains_range(container, lb_rs, 1 << 16, typecode)) {
+ return false;
+ }
+ assert(ie < hlc_sz); // would indicate an algorithmic bug
+ container = ra_get_container_at_index(&r->high_low_container, ie, &typecode);
+ if (!container_contains_range(container, 0, lb_re, typecode)) {
+ return false;
+ }
+ for (int32_t i = is + 1; i < ie; ++i) {
+ container = ra_get_container_at_index(&r->high_low_container, i, &typecode);
+ if (!container_is_full(container, typecode) ) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool roaring_bitmap_is_strict_subset(const roaring_bitmap_t *ra1,
+ const roaring_bitmap_t *ra2) {
+ return (roaring_bitmap_get_cardinality(ra2) >
+ roaring_bitmap_get_cardinality(ra1) &&
+ roaring_bitmap_is_subset(ra1, ra2));
+}
+
+
+/*
+ * FROZEN SERIALIZATION FORMAT DESCRIPTION
+ *
+ * -- (beginning must be aligned by 32 bytes) --
+ * uint64_t[BITSET_CONTAINER_SIZE_IN_WORDS * num_bitset_containers]
+ * rle16_t[total number of rle elements in all run containers]
+ * uint16_t[total number of array elements in all array containers]
+ * uint16_t[num_containers]
+ * uint16_t[num_containers]
+ * uint8_t[num_containers]
+ * uint32_t
+ *
+ * is a 4-byte value which is a bit union of FROZEN_COOKIE (15 bits)
+ * and the number of containers (17 bits).
+ *
+ * stores number of elements for every container.
+ * Its meaning depends on container type.
+ * For array and bitset containers, this value is the container cardinality minus one.
+ * For run container, it is the number of rle_t elements (n_runs).
+ *
+ * ,, are flat arrays of elements of
+ * all containers of respective type.
+ *
+ * <*_data> and are kept close together because they are not accessed
+ * during deserilization. This may reduce IO in case of large mapped bitmaps.
+ * All members have their native alignments during deserilization except ,
+ * which is not guaranteed to be aligned by 4 bytes.
+ */
+
+size_t roaring_bitmap_frozen_size_in_bytes(const roaring_bitmap_t *rb) {
+ const roaring_array_t *ra = &rb->high_low_container;
+ size_t num_bytes = 0;
+ for (int32_t i = 0; i < ra->size; i++) {
+ switch (ra->typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ num_bytes += BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+ break;
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ const run_container_t *run =
+ (const run_container_t *) ra->containers[i];
+ num_bytes += run->n_runs * sizeof(rle16_t);
+ break;
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ const array_container_t *array =
+ (const array_container_t *) ra->containers[i];
+ num_bytes += array->cardinality * sizeof(uint16_t);
+ break;
+ }
+ default:
+ __builtin_unreachable();
+ }
+ }
+ num_bytes += (2 + 2 + 1) * ra->size; // keys, counts, typecodes
+ num_bytes += 4; // header
+ return num_bytes;
+}
+
+inline static void *arena_alloc(char **arena, size_t num_bytes) {
+ char *res = *arena;
+ *arena += num_bytes;
+ return res;
+}
+
+void roaring_bitmap_frozen_serialize(const roaring_bitmap_t *rb, char *buf) {
+ /*
+ * Note: we do not require user to supply spicificly aligned buffer.
+ * Thus we have to use memcpy() everywhere.
+ */
+
+ const roaring_array_t *ra = &rb->high_low_container;
+
+ size_t bitset_zone_size = 0;
+ size_t run_zone_size = 0;
+ size_t array_zone_size = 0;
+ for (int32_t i = 0; i < ra->size; i++) {
+ switch (ra->typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ bitset_zone_size +=
+ BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+ break;
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ const run_container_t *run =
+ (const run_container_t *) ra->containers[i];
+ run_zone_size += run->n_runs * sizeof(rle16_t);
+ break;
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ const array_container_t *array =
+ (const array_container_t *) ra->containers[i];
+ array_zone_size += array->cardinality * sizeof(uint16_t);
+ break;
+ }
+ default:
+ __builtin_unreachable();
+ }
+ }
+
+ uint64_t *bitset_zone = (uint64_t *)arena_alloc(&buf, bitset_zone_size);
+ rle16_t *run_zone = (rle16_t *)arena_alloc(&buf, run_zone_size);
+ uint16_t *array_zone = (uint16_t *)arena_alloc(&buf, array_zone_size);
+ uint16_t *key_zone = (uint16_t *)arena_alloc(&buf, 2*ra->size);
+ uint16_t *count_zone = (uint16_t *)arena_alloc(&buf, 2*ra->size);
+ uint8_t *typecode_zone = (uint8_t *)arena_alloc(&buf, ra->size);
+ uint32_t *header_zone = (uint32_t *)arena_alloc(&buf, 4);
+
+ for (int32_t i = 0; i < ra->size; i++) {
+ uint16_t count;
+ switch (ra->typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ const bitset_container_t *bitset =
+ (const bitset_container_t *) ra->containers[i];
+ memcpy(bitset_zone, bitset->array,
+ BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t));
+ bitset_zone += BITSET_CONTAINER_SIZE_IN_WORDS;
+ if (bitset->cardinality != BITSET_UNKNOWN_CARDINALITY) {
+ count = bitset->cardinality - 1;
+ } else {
+ count = bitset_container_compute_cardinality(bitset) - 1;
+ }
+ break;
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ const run_container_t *run =
+ (const run_container_t *) ra->containers[i];
+ size_t num_bytes = run->n_runs * sizeof(rle16_t);
+ memcpy(run_zone, run->runs, num_bytes);
+ run_zone += run->n_runs;
+ count = run->n_runs;
+ break;
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ const array_container_t *array =
+ (const array_container_t *) ra->containers[i];
+ size_t num_bytes = array->cardinality * sizeof(uint16_t);
+ memcpy(array_zone, array->array, num_bytes);
+ array_zone += array->cardinality;
+ count = array->cardinality - 1;
+ break;
+ }
+ default:
+ __builtin_unreachable();
+ }
+ memcpy(&count_zone[i], &count, 2);
+ }
+ memcpy(key_zone, ra->keys, ra->size * sizeof(uint16_t));
+ memcpy(typecode_zone, ra->typecodes, ra->size * sizeof(uint8_t));
+ uint32_t header = ((uint32_t)ra->size << 15) | FROZEN_COOKIE;
+ memcpy(header_zone, &header, 4);
+}
+
+const roaring_bitmap_t *
+roaring_bitmap_frozen_view(const char *buf, size_t length) {
+ if ((uintptr_t)buf % 32 != 0) {
+ return NULL;
+ }
+
+ // cookie and num_containers
+ if (length < 4) {
+ return NULL;
+ }
+ uint32_t header;
+ memcpy(&header, buf + length - 4, 4); // header may be misaligned
+ if ((header & 0x7FFF) != FROZEN_COOKIE) {
+ return NULL;
+ }
+ int32_t num_containers = (header >> 15);
+
+ // typecodes, counts and keys
+ if (length < 4 + (size_t)num_containers * (1 + 2 + 2)) {
+ return NULL;
+ }
+ uint16_t *keys = (uint16_t *)(buf + length - 4 - num_containers * 5);
+ uint16_t *counts = (uint16_t *)(buf + length - 4 - num_containers * 3);
+ uint8_t *typecodes = (uint8_t *)(buf + length - 4 - num_containers * 1);
+
+ // {bitset,array,run}_zone
+ int32_t num_bitset_containers = 0;
+ int32_t num_run_containers = 0;
+ int32_t num_array_containers = 0;
+ size_t bitset_zone_size = 0;
+ size_t run_zone_size = 0;
+ size_t array_zone_size = 0;
+ for (int32_t i = 0; i < num_containers; i++) {
+ switch (typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ num_bitset_containers++;
+ bitset_zone_size += BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ num_run_containers++;
+ run_zone_size += counts[i] * sizeof(rle16_t);
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ num_array_containers++;
+ array_zone_size += (counts[i] + UINT32_C(1)) * sizeof(uint16_t);
+ break;
+ default:
+ return NULL;
+ }
+ }
+ if (length != bitset_zone_size + run_zone_size + array_zone_size +
+ 5 * num_containers + 4) {
+ return NULL;
+ }
+ uint64_t *bitset_zone = (uint64_t*) (buf);
+ rle16_t *run_zone = (rle16_t*) (buf + bitset_zone_size);
+ uint16_t *array_zone = (uint16_t*) (buf + bitset_zone_size + run_zone_size);
+
+ size_t alloc_size = 0;
+ alloc_size += sizeof(roaring_bitmap_t);
+ alloc_size += num_containers * sizeof(void *);
+ alloc_size += num_bitset_containers * sizeof(bitset_container_t);
+ alloc_size += num_run_containers * sizeof(run_container_t);
+ alloc_size += num_array_containers * sizeof(array_container_t);
+
+ char *arena = (char *)malloc(alloc_size);
+ if (arena == NULL) {
+ return NULL;
+ }
+
+ roaring_bitmap_t *rb = (roaring_bitmap_t *)
+ arena_alloc(&arena, sizeof(roaring_bitmap_t));
+ rb->high_low_container.flags = ROARING_FLAG_FROZEN;
+ rb->high_low_container.allocation_size = num_containers;
+ rb->high_low_container.size = num_containers;
+ rb->high_low_container.keys = (uint16_t *)keys;
+ rb->high_low_container.typecodes = (uint8_t *)typecodes;
+ rb->high_low_container.containers =
+ (void **)arena_alloc(&arena, sizeof(void*) * num_containers);
+ for (int32_t i = 0; i < num_containers; i++) {
+ switch (typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ bitset_container_t *bitset = (bitset_container_t *)
+ arena_alloc(&arena, sizeof(bitset_container_t));
+ bitset->array = bitset_zone;
+ bitset->cardinality = counts[i] + UINT32_C(1);
+ rb->high_low_container.containers[i] = bitset;
+ bitset_zone += BITSET_CONTAINER_SIZE_IN_WORDS;
+ break;
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ run_container_t *run = (run_container_t *)
+ arena_alloc(&arena, sizeof(run_container_t));
+ run->capacity = counts[i];
+ run->n_runs = counts[i];
+ run->runs = run_zone;
+ rb->high_low_container.containers[i] = run;
+ run_zone += run->n_runs;
+ break;
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ array_container_t *array = (array_container_t *)
+ arena_alloc(&arena, sizeof(array_container_t));
+ array->capacity = counts[i] + UINT32_C(1);
+ array->cardinality = counts[i] + UINT32_C(1);
+ array->array = array_zone;
+ rb->high_low_container.containers[i] = array;
+ array_zone += counts[i] + UINT32_C(1);
+ break;
+ }
+ default:
+ free(arena);
+ return NULL;
+ }
+ }
+
+ return rb;
+}
+/* end file src/roaring.c */
+/* begin file src/roaring_array.c */
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+// Convention: [0,ra->size) all elements are initialized
+// [ra->size, ra->allocation_size) is junk and contains nothing needing freeing
+
+static bool realloc_array(roaring_array_t *ra, int32_t new_capacity) {
+ // because we combine the allocations, it is not possible to use realloc
+ /*ra->keys =
+ (uint16_t *)realloc(ra->keys, sizeof(uint16_t) * new_capacity);
+ra->containers =
+ (void **)realloc(ra->containers, sizeof(void *) * new_capacity);
+ra->typecodes =
+ (uint8_t *)realloc(ra->typecodes, sizeof(uint8_t) * new_capacity);
+if (!ra->keys || !ra->containers || !ra->typecodes) {
+ free(ra->keys);
+ free(ra->containers);
+ free(ra->typecodes);
+ return false;
+}*/
+
+ if ( new_capacity == 0 ) {
+ free(ra->containers);
+ ra->containers = NULL;
+ ra->keys = NULL;
+ ra->typecodes = NULL;
+ ra->allocation_size = 0;
+ return true;
+ }
+ const size_t memoryneeded =
+ new_capacity * (sizeof(uint16_t) + sizeof(void *) + sizeof(uint8_t));
+ void *bigalloc = malloc(memoryneeded);
+ if (!bigalloc) return false;
+ void *oldbigalloc = ra->containers;
+ void **newcontainers = (void **)bigalloc;
+ uint16_t *newkeys = (uint16_t *)(newcontainers + new_capacity);
+ uint8_t *newtypecodes = (uint8_t *)(newkeys + new_capacity);
+ assert((char *)(newtypecodes + new_capacity) ==
+ (char *)bigalloc + memoryneeded);
+ if(ra->size > 0) {
+ memcpy(newcontainers, ra->containers, sizeof(void *) * ra->size);
+ memcpy(newkeys, ra->keys, sizeof(uint16_t) * ra->size);
+ memcpy(newtypecodes, ra->typecodes, sizeof(uint8_t) * ra->size);
+ }
+ ra->containers = newcontainers;
+ ra->keys = newkeys;
+ ra->typecodes = newtypecodes;
+ ra->allocation_size = new_capacity;
+ free(oldbigalloc);
+ return true;
+}
+
+bool ra_init_with_capacity(roaring_array_t *new_ra, uint32_t cap) {
+ if (!new_ra) return false;
+ ra_init(new_ra);
+
+ if (cap > INT32_MAX) { return false; }
+
+ if(cap > 0) {
+ void *bigalloc =
+ malloc(cap * (sizeof(uint16_t) + sizeof(void *) + sizeof(uint8_t)));
+ if( bigalloc == NULL ) return false;
+ new_ra->containers = (void **)bigalloc;
+ new_ra->keys = (uint16_t *)(new_ra->containers + cap);
+ new_ra->typecodes = (uint8_t *)(new_ra->keys + cap);
+ // Narrowing is safe because of above check
+ new_ra->allocation_size = (int32_t)cap;
+ }
+ return true;
+}
+
+int ra_shrink_to_fit(roaring_array_t *ra) {
+ int savings = (ra->allocation_size - ra->size) *
+ (sizeof(uint16_t) + sizeof(void *) + sizeof(uint8_t));
+ if (!realloc_array(ra, ra->size)) {
+ return 0;
+ }
+ ra->allocation_size = ra->size;
+ return savings;
+}
+
+void ra_init(roaring_array_t *new_ra) {
+ if (!new_ra) { return; }
+ new_ra->keys = NULL;
+ new_ra->containers = NULL;
+ new_ra->typecodes = NULL;
+
+ new_ra->allocation_size = 0;
+ new_ra->size = 0;
+ new_ra->flags = 0;
+}
+
+bool ra_copy(const roaring_array_t *source, roaring_array_t *dest,
+ bool copy_on_write) {
+ if (!ra_init_with_capacity(dest, source->size)) return false;
+ dest->size = source->size;
+ dest->allocation_size = source->size;
+ if(dest->size > 0) {
+ memcpy(dest->keys, source->keys, dest->size * sizeof(uint16_t));
+ }
+ // we go through the containers, turning them into shared containers...
+ if (copy_on_write) {
+ for (int32_t i = 0; i < dest->size; ++i) {
+ source->containers[i] = get_copy_of_container(
+ source->containers[i], &source->typecodes[i], copy_on_write);
+ }
+ // we do a shallow copy to the other bitmap
+ if(dest->size > 0) {
+ memcpy(dest->containers, source->containers,
+ dest->size * sizeof(void *));
+ memcpy(dest->typecodes, source->typecodes,
+ dest->size * sizeof(uint8_t));
+ }
+ } else {
+ if(dest->size > 0) {
+ memcpy(dest->typecodes, source->typecodes,
+ dest->size * sizeof(uint8_t));
+ }
+ for (int32_t i = 0; i < dest->size; i++) {
+ dest->containers[i] =
+ container_clone(source->containers[i], source->typecodes[i]);
+ if (dest->containers[i] == NULL) {
+ for (int32_t j = 0; j < i; j++) {
+ container_free(dest->containers[j], dest->typecodes[j]);
+ }
+ ra_clear_without_containers(dest);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ra_overwrite(const roaring_array_t *source, roaring_array_t *dest,
+ bool copy_on_write) {
+ ra_clear_containers(dest); // we are going to overwrite them
+ if (dest->allocation_size < source->size) {
+ if (!realloc_array(dest, source->size)) {
+ return false;
+ }
+ }
+ dest->size = source->size;
+ memcpy(dest->keys, source->keys, dest->size * sizeof(uint16_t));
+ // we go through the containers, turning them into shared containers...
+ if (copy_on_write) {
+ for (int32_t i = 0; i < dest->size; ++i) {
+ source->containers[i] = get_copy_of_container(
+ source->containers[i], &source->typecodes[i], copy_on_write);
+ }
+ // we do a shallow copy to the other bitmap
+ memcpy(dest->containers, source->containers,
+ dest->size * sizeof(void *));
+ memcpy(dest->typecodes, source->typecodes,
+ dest->size * sizeof(uint8_t));
+ } else {
+ memcpy(dest->typecodes, source->typecodes,
+ dest->size * sizeof(uint8_t));
+ for (int32_t i = 0; i < dest->size; i++) {
+ dest->containers[i] =
+ container_clone(source->containers[i], source->typecodes[i]);
+ if (dest->containers[i] == NULL) {
+ for (int32_t j = 0; j < i; j++) {
+ container_free(dest->containers[j], dest->typecodes[j]);
+ }
+ ra_clear_without_containers(dest);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void ra_clear_containers(roaring_array_t *ra) {
+ for (int32_t i = 0; i < ra->size; ++i) {
+ container_free(ra->containers[i], ra->typecodes[i]);
+ }
+}
+
+void ra_reset(roaring_array_t *ra) {
+ ra_clear_containers(ra);
+ ra->size = 0;
+ ra_shrink_to_fit(ra);
+}
+
+void ra_clear_without_containers(roaring_array_t *ra) {
+ free(ra->containers); // keys and typecodes are allocated with containers
+ ra->size = 0;
+ ra->allocation_size = 0;
+ ra->containers = NULL;
+ ra->keys = NULL;
+ ra->typecodes = NULL;
+}
+
+void ra_clear(roaring_array_t *ra) {
+ ra_clear_containers(ra);
+ ra_clear_without_containers(ra);
+}
+
+bool extend_array(roaring_array_t *ra, int32_t k) {
+ int32_t desired_size = ra->size + k;
+ assert(desired_size <= MAX_CONTAINERS);
+ if (desired_size > ra->allocation_size) {
+ int32_t new_capacity =
+ (ra->size < 1024) ? 2 * desired_size : 5 * desired_size / 4;
+ if (new_capacity > MAX_CONTAINERS) {
+ new_capacity = MAX_CONTAINERS;
+ }
+
+ return realloc_array(ra, new_capacity);
+ }
+ return true;
+}
+
+void ra_append(roaring_array_t *ra, uint16_t key, void *container,
+ uint8_t typecode) {
+ extend_array(ra, 1);
+ const int32_t pos = ra->size;
+
+ ra->keys[pos] = key;
+ ra->containers[pos] = container;
+ ra->typecodes[pos] = typecode;
+ ra->size++;
+}
+
+void ra_append_copy(roaring_array_t *ra, const roaring_array_t *sa,
+ uint16_t index, bool copy_on_write) {
+ extend_array(ra, 1);
+ const int32_t pos = ra->size;
+
+ // old contents is junk not needing freeing
+ ra->keys[pos] = sa->keys[index];
+ // the shared container will be in two bitmaps
+ if (copy_on_write) {
+ sa->containers[index] = get_copy_of_container(
+ sa->containers[index], &sa->typecodes[index], copy_on_write);
+ ra->containers[pos] = sa->containers[index];
+ ra->typecodes[pos] = sa->typecodes[index];
+ } else {
+ ra->containers[pos] =
+ container_clone(sa->containers[index], sa->typecodes[index]);
+ ra->typecodes[pos] = sa->typecodes[index];
+ }
+ ra->size++;
+}
+
+void ra_append_copies_until(roaring_array_t *ra, const roaring_array_t *sa,
+ uint16_t stopping_key, bool copy_on_write) {
+ for (int32_t i = 0; i < sa->size; ++i) {
+ if (sa->keys[i] >= stopping_key) break;
+ ra_append_copy(ra, sa, i, copy_on_write);
+ }
+}
+
+void ra_append_copy_range(roaring_array_t *ra, const roaring_array_t *sa,
+ int32_t start_index, int32_t end_index,
+ bool copy_on_write) {
+ extend_array(ra, end_index - start_index);
+ for (int32_t i = start_index; i < end_index; ++i) {
+ const int32_t pos = ra->size;
+ ra->keys[pos] = sa->keys[i];
+ if (copy_on_write) {
+ sa->containers[i] = get_copy_of_container(
+ sa->containers[i], &sa->typecodes[i], copy_on_write);
+ ra->containers[pos] = sa->containers[i];
+ ra->typecodes[pos] = sa->typecodes[i];
+ } else {
+ ra->containers[pos] =
+ container_clone(sa->containers[i], sa->typecodes[i]);
+ ra->typecodes[pos] = sa->typecodes[i];
+ }
+ ra->size++;
+ }
+}
+
+void ra_append_copies_after(roaring_array_t *ra, const roaring_array_t *sa,
+ uint16_t before_start, bool copy_on_write) {
+ int start_location = ra_get_index(sa, before_start);
+ if (start_location >= 0)
+ ++start_location;
+ else
+ start_location = -start_location - 1;
+ ra_append_copy_range(ra, sa, start_location, sa->size, copy_on_write);
+}
+
+void ra_append_move_range(roaring_array_t *ra, roaring_array_t *sa,
+ int32_t start_index, int32_t end_index) {
+ extend_array(ra, end_index - start_index);
+
+ for (int32_t i = start_index; i < end_index; ++i) {
+ const int32_t pos = ra->size;
+
+ ra->keys[pos] = sa->keys[i];
+ ra->containers[pos] = sa->containers[i];
+ ra->typecodes[pos] = sa->typecodes[i];
+ ra->size++;
+ }
+}
+
+void ra_append_range(roaring_array_t *ra, roaring_array_t *sa,
+ int32_t start_index, int32_t end_index,
+ bool copy_on_write) {
+ extend_array(ra, end_index - start_index);
+
+ for (int32_t i = start_index; i < end_index; ++i) {
+ const int32_t pos = ra->size;
+ ra->keys[pos] = sa->keys[i];
+ if (copy_on_write) {
+ sa->containers[i] = get_copy_of_container(
+ sa->containers[i], &sa->typecodes[i], copy_on_write);
+ ra->containers[pos] = sa->containers[i];
+ ra->typecodes[pos] = sa->typecodes[i];
+ } else {
+ ra->containers[pos] =
+ container_clone(sa->containers[i], sa->typecodes[i]);
+ ra->typecodes[pos] = sa->typecodes[i];
+ }
+ ra->size++;
+ }
+}
+
+uint16_t ra_get_key_at_index(const roaring_array_t *ra, uint16_t i) {
+ return ra->keys[i];
+}
+
+// everything skipped over is freed
+int32_t ra_advance_until_freeing(roaring_array_t *ra, uint16_t x, int32_t pos) {
+ while (pos < ra->size && ra->keys[pos] < x) {
+ container_free(ra->containers[pos], ra->typecodes[pos]);
+ ++pos;
+ }
+ return pos;
+}
+
+void ra_insert_new_key_value_at(roaring_array_t *ra, int32_t i, uint16_t key,
+ void *container, uint8_t typecode) {
+ extend_array(ra, 1);
+ // May be an optimization opportunity with DIY memmove
+ memmove(&(ra->keys[i + 1]), &(ra->keys[i]),
+ sizeof(uint16_t) * (ra->size - i));
+ memmove(&(ra->containers[i + 1]), &(ra->containers[i]),
+ sizeof(void *) * (ra->size - i));
+ memmove(&(ra->typecodes[i + 1]), &(ra->typecodes[i]),
+ sizeof(uint8_t) * (ra->size - i));
+ ra->keys[i] = key;
+ ra->containers[i] = container;
+ ra->typecodes[i] = typecode;
+ ra->size++;
+}
+
+// note: Java routine set things to 0, enabling GC.
+// Java called it "resize" but it was always used to downsize.
+// Allowing upsize would break the conventions about
+// valid containers below ra->size.
+
+void ra_downsize(roaring_array_t *ra, int32_t new_length) {
+ assert(new_length <= ra->size);
+ ra->size = new_length;
+}
+
+void ra_remove_at_index(roaring_array_t *ra, int32_t i) {
+ memmove(&(ra->containers[i]), &(ra->containers[i + 1]),
+ sizeof(void *) * (ra->size - i - 1));
+ memmove(&(ra->keys[i]), &(ra->keys[i + 1]),
+ sizeof(uint16_t) * (ra->size - i - 1));
+ memmove(&(ra->typecodes[i]), &(ra->typecodes[i + 1]),
+ sizeof(uint8_t) * (ra->size - i - 1));
+ ra->size--;
+}
+
+void ra_remove_at_index_and_free(roaring_array_t *ra, int32_t i) {
+ container_free(ra->containers[i], ra->typecodes[i]);
+ ra_remove_at_index(ra, i);
+}
+
+// used in inplace andNot only, to slide left the containers from
+// the mutated RoaringBitmap that are after the largest container of
+// the argument RoaringBitmap. In use it should be followed by a call to
+// downsize.
+//
+void ra_copy_range(roaring_array_t *ra, uint32_t begin, uint32_t end,
+ uint32_t new_begin) {
+ assert(begin <= end);
+ assert(new_begin < begin);
+
+ const int range = end - begin;
+
+ // We ensure to previously have freed overwritten containers
+ // that are not copied elsewhere
+
+ memmove(&(ra->containers[new_begin]), &(ra->containers[begin]),
+ sizeof(void *) * range);
+ memmove(&(ra->keys[new_begin]), &(ra->keys[begin]),
+ sizeof(uint16_t) * range);
+ memmove(&(ra->typecodes[new_begin]), &(ra->typecodes[begin]),
+ sizeof(uint8_t) * range);
+}
+
+void ra_shift_tail(roaring_array_t *ra, int32_t count, int32_t distance) {
+ if (distance > 0) {
+ extend_array(ra, distance);
+ }
+ int32_t srcpos = ra->size - count;
+ int32_t dstpos = srcpos + distance;
+ memmove(&(ra->keys[dstpos]), &(ra->keys[srcpos]),
+ sizeof(uint16_t) * count);
+ memmove(&(ra->containers[dstpos]), &(ra->containers[srcpos]),
+ sizeof(void *) * count);
+ memmove(&(ra->typecodes[dstpos]), &(ra->typecodes[srcpos]),
+ sizeof(uint8_t) * count);
+ ra->size += distance;
+}
+
+
+void ra_to_uint32_array(const roaring_array_t *ra, uint32_t *ans) {
+ size_t ctr = 0;
+ for (int32_t i = 0; i < ra->size; ++i) {
+ int num_added = container_to_uint32_array(
+ ans + ctr, ra->containers[i], ra->typecodes[i],
+ ((uint32_t)ra->keys[i]) << 16);
+ ctr += num_added;
+ }
+}
+
+bool ra_range_uint32_array(const roaring_array_t *ra, size_t offset, size_t limit, uint32_t *ans) {
+ size_t ctr = 0;
+ size_t dtr = 0;
+
+ size_t t_limit = 0;
+
+ bool first = false;
+ size_t first_skip = 0;
+
+ uint32_t *t_ans = NULL;
+ size_t cur_len = 0;
+
+ for (int i = 0; i < ra->size; ++i) {
+
+ const void *container = container_unwrap_shared(ra->containers[i], &ra->typecodes[i]);
+ switch (ra->typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ t_limit = ((const bitset_container_t *)container)->cardinality;
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ t_limit = ((const array_container_t *)container)->cardinality;
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ t_limit = run_container_cardinality((const run_container_t *)container);
+ break;
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ __builtin_unreachable();
+ }
+ if (ctr + t_limit - 1 >= offset && ctr < offset + limit){
+ if (!first){
+ //first_skip = t_limit - (ctr + t_limit - offset);
+ first_skip = offset - ctr;
+ first = true;
+ t_ans = (uint32_t *)malloc(sizeof(*t_ans) * (first_skip + limit));
+ if(t_ans == NULL) {
+ return false;
+ }
+ memset(t_ans, 0, sizeof(*t_ans) * (first_skip + limit)) ;
+ cur_len = first_skip + limit;
+ }
+ if (dtr + t_limit > cur_len){
+ uint32_t * append_ans = (uint32_t *)malloc(sizeof(*append_ans) * (cur_len + t_limit));
+ if(append_ans == NULL) {
+ if(t_ans != NULL) free(t_ans);
+ return false;
+ }
+ memset(append_ans, 0, sizeof(*append_ans) * (cur_len + t_limit));
+ cur_len = cur_len + t_limit;
+ memcpy(append_ans, t_ans, dtr * sizeof(uint32_t));
+ free(t_ans);
+ t_ans = append_ans;
+ }
+ switch (ra->typecodes[i]) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ container_to_uint32_array(
+ t_ans + dtr, (const bitset_container_t *)container, ra->typecodes[i],
+ ((uint32_t)ra->keys[i]) << 16);
+ break;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ container_to_uint32_array(
+ t_ans + dtr, (const array_container_t *)container, ra->typecodes[i],
+ ((uint32_t)ra->keys[i]) << 16);
+ break;
+ case RUN_CONTAINER_TYPE_CODE:
+ container_to_uint32_array(
+ t_ans + dtr, (const run_container_t *)container, ra->typecodes[i],
+ ((uint32_t)ra->keys[i]) << 16);
+ break;
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ __builtin_unreachable();
+ }
+ dtr += t_limit;
+ }
+ ctr += t_limit;
+ if (dtr-first_skip >= limit) break;
+ }
+ if(t_ans != NULL) {
+ memcpy(ans, t_ans+first_skip, limit * sizeof(uint32_t));
+ free(t_ans);
+ }
+ return true;
+}
+
+bool ra_has_run_container(const roaring_array_t *ra) {
+ for (int32_t k = 0; k < ra->size; ++k) {
+ if (get_container_type(ra->containers[k], ra->typecodes[k]) ==
+ RUN_CONTAINER_TYPE_CODE)
+ return true;
+ }
+ return false;
+}
+
+uint32_t ra_portable_header_size(const roaring_array_t *ra) {
+ if (ra_has_run_container(ra)) {
+ if (ra->size <
+ NO_OFFSET_THRESHOLD) { // for small bitmaps, we omit the offsets
+ return 4 + (ra->size + 7) / 8 + 4 * ra->size;
+ }
+ return 4 + (ra->size + 7) / 8 +
+ 8 * ra->size; // - 4 because we pack the size with the cookie
+ } else {
+ return 4 + 4 + 8 * ra->size;
+ }
+}
+
+size_t ra_portable_size_in_bytes(const roaring_array_t *ra) {
+ size_t count = ra_portable_header_size(ra);
+
+ for (int32_t k = 0; k < ra->size; ++k) {
+ count += container_size_in_bytes(ra->containers[k], ra->typecodes[k]);
+ }
+ return count;
+}
+
+size_t ra_portable_serialize(const roaring_array_t *ra, char *buf) {
+ char *initbuf = buf;
+ uint32_t startOffset = 0;
+ bool hasrun = ra_has_run_container(ra);
+ if (hasrun) {
+ uint32_t cookie = SERIAL_COOKIE | ((ra->size - 1) << 16);
+ memcpy(buf, &cookie, sizeof(cookie));
+ buf += sizeof(cookie);
+ uint32_t s = (ra->size + 7) / 8;
+ uint8_t *bitmapOfRunContainers = (uint8_t *)calloc(s, 1);
+ assert(bitmapOfRunContainers != NULL); // todo: handle
+ for (int32_t i = 0; i < ra->size; ++i) {
+ if (get_container_type(ra->containers[i], ra->typecodes[i]) ==
+ RUN_CONTAINER_TYPE_CODE) {
+ bitmapOfRunContainers[i / 8] |= (1 << (i % 8));
+ }
+ }
+ memcpy(buf, bitmapOfRunContainers, s);
+ buf += s;
+ free(bitmapOfRunContainers);
+ if (ra->size < NO_OFFSET_THRESHOLD) {
+ startOffset = 4 + 4 * ra->size + s;
+ } else {
+ startOffset = 4 + 8 * ra->size + s;
+ }
+ } else { // backwards compatibility
+ uint32_t cookie = SERIAL_COOKIE_NO_RUNCONTAINER;
+
+ memcpy(buf, &cookie, sizeof(cookie));
+ buf += sizeof(cookie);
+ memcpy(buf, &ra->size, sizeof(ra->size));
+ buf += sizeof(ra->size);
+
+ startOffset = 4 + 4 + 4 * ra->size + 4 * ra->size;
+ }
+ for (int32_t k = 0; k < ra->size; ++k) {
+ memcpy(buf, &ra->keys[k], sizeof(ra->keys[k]));
+ buf += sizeof(ra->keys[k]);
+ // get_cardinality returns a value in [1,1<<16], subtracting one
+ // we get [0,1<<16 - 1] which fits in 16 bits
+ uint16_t card = (uint16_t)(
+ container_get_cardinality(ra->containers[k], ra->typecodes[k]) - 1);
+ memcpy(buf, &card, sizeof(card));
+ buf += sizeof(card);
+ }
+ if ((!hasrun) || (ra->size >= NO_OFFSET_THRESHOLD)) {
+ // writing the containers offsets
+ for (int32_t k = 0; k < ra->size; k++) {
+ memcpy(buf, &startOffset, sizeof(startOffset));
+ buf += sizeof(startOffset);
+ startOffset =
+ startOffset +
+ container_size_in_bytes(ra->containers[k], ra->typecodes[k]);
+ }
+ }
+ for (int32_t k = 0; k < ra->size; ++k) {
+ buf += container_write(ra->containers[k], ra->typecodes[k], buf);
+ }
+ return buf - initbuf;
+}
+
+// Quickly checks whether there is a serialized bitmap at the pointer,
+// not exceeding size "maxbytes" in bytes. This function does not allocate
+// memory dynamically.
+//
+// This function returns 0 if and only if no valid bitmap is found.
+// Otherwise, it returns how many bytes are occupied.
+//
+size_t ra_portable_deserialize_size(const char *buf, const size_t maxbytes) {
+ size_t bytestotal = sizeof(int32_t);// for cookie
+ if(bytestotal > maxbytes) return 0;
+ uint32_t cookie;
+ memcpy(&cookie, buf, sizeof(int32_t));
+ buf += sizeof(uint32_t);
+ if ((cookie & 0xFFFF) != SERIAL_COOKIE &&
+ cookie != SERIAL_COOKIE_NO_RUNCONTAINER) {
+ return 0;
+ }
+ int32_t size;
+
+ if ((cookie & 0xFFFF) == SERIAL_COOKIE)
+ size = (cookie >> 16) + 1;
+ else {
+ bytestotal += sizeof(int32_t);
+ if(bytestotal > maxbytes) return 0;
+ memcpy(&size, buf, sizeof(int32_t));
+ buf += sizeof(uint32_t);
+ }
+ if (size > (1<<16)) {
+ return 0; // logically impossible
+ }
+ char *bitmapOfRunContainers = NULL;
+ bool hasrun = (cookie & 0xFFFF) == SERIAL_COOKIE;
+ if (hasrun) {
+ int32_t s = (size + 7) / 8;
+ bytestotal += s;
+ if(bytestotal > maxbytes) return 0;
+ bitmapOfRunContainers = (char *)buf;
+ buf += s;
+ }
+ bytestotal += size * 2 * sizeof(uint16_t);
+ if(bytestotal > maxbytes) return 0;
+ uint16_t *keyscards = (uint16_t *)buf;
+ buf += size * 2 * sizeof(uint16_t);
+ if ((!hasrun) || (size >= NO_OFFSET_THRESHOLD)) {
+ // skipping the offsets
+ bytestotal += size * 4;
+ if(bytestotal > maxbytes) return 0;
+ buf += size * 4;
+ }
+ // Reading the containers
+ for (int32_t k = 0; k < size; ++k) {
+ uint16_t tmp;
+ memcpy(&tmp, keyscards + 2*k+1, sizeof(tmp));
+ uint32_t thiscard = tmp + 1;
+ bool isbitmap = (thiscard > DEFAULT_MAX_SIZE);
+ bool isrun = false;
+ if(hasrun) {
+ if((bitmapOfRunContainers[k / 8] & (1 << (k % 8))) != 0) {
+ isbitmap = false;
+ isrun = true;
+ }
+ }
+ if (isbitmap) {
+ size_t containersize = BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+ bytestotal += containersize;
+ if(bytestotal > maxbytes) return 0;
+ buf += containersize;
+ } else if (isrun) {
+ bytestotal += sizeof(uint16_t);
+ if(bytestotal > maxbytes) return 0;
+ uint16_t n_runs;
+ memcpy(&n_runs, buf, sizeof(uint16_t));
+ buf += sizeof(uint16_t);
+ size_t containersize = n_runs * sizeof(rle16_t);
+ bytestotal += containersize;
+ if(bytestotal > maxbytes) return 0;
+ buf += containersize;
+ } else {
+ size_t containersize = thiscard * sizeof(uint16_t);
+ bytestotal += containersize;
+ if(bytestotal > maxbytes) return 0;
+ buf += containersize;
+ }
+ }
+ return bytestotal;
+}
+
+
+// this function populates answer from the content of buf (reading up to maxbytes bytes).
+// The function returns false if a properly serialized bitmap cannot be found.
+// if it returns true, readbytes is populated by how many bytes were read, we have that *readbytes <= maxbytes.
+bool ra_portable_deserialize(roaring_array_t *answer, const char *buf, const size_t maxbytes, size_t * readbytes) {
+ *readbytes = sizeof(int32_t);// for cookie
+ if(*readbytes > maxbytes) {
+ fprintf(stderr, "Ran out of bytes while reading first 4 bytes.\n");
+ return false;
+ }
+ uint32_t cookie;
+ memcpy(&cookie, buf, sizeof(int32_t));
+ buf += sizeof(uint32_t);
+ if ((cookie & 0xFFFF) != SERIAL_COOKIE &&
+ cookie != SERIAL_COOKIE_NO_RUNCONTAINER) {
+ fprintf(stderr, "I failed to find one of the right cookies. Found %" PRIu32 "\n",
+ cookie);
+ return false;
+ }
+ int32_t size;
+
+ if ((cookie & 0xFFFF) == SERIAL_COOKIE)
+ size = (cookie >> 16) + 1;
+ else {
+ *readbytes += sizeof(int32_t);
+ if(*readbytes > maxbytes) {
+ fprintf(stderr, "Ran out of bytes while reading second part of the cookie.\n");
+ return false;
+ }
+ memcpy(&size, buf, sizeof(int32_t));
+ buf += sizeof(uint32_t);
+ }
+ if (size > (1<<16)) {
+ fprintf(stderr, "You cannot have so many containers, the data must be corrupted: %" PRId32 "\n",
+ size);
+ return false; // logically impossible
+ }
+ const char *bitmapOfRunContainers = NULL;
+ bool hasrun = (cookie & 0xFFFF) == SERIAL_COOKIE;
+ if (hasrun) {
+ int32_t s = (size + 7) / 8;
+ *readbytes += s;
+ if(*readbytes > maxbytes) {// data is corrupted?
+ fprintf(stderr, "Ran out of bytes while reading run bitmap.\n");
+ return false;
+ }
+ bitmapOfRunContainers = buf;
+ buf += s;
+ }
+ uint16_t *keyscards = (uint16_t *)buf;
+
+ *readbytes += size * 2 * sizeof(uint16_t);
+ if(*readbytes > maxbytes) {
+ fprintf(stderr, "Ran out of bytes while reading key-cardinality array.\n");
+ return false;
+ }
+ buf += size * 2 * sizeof(uint16_t);
+
+ bool is_ok = ra_init_with_capacity(answer, size);
+ if (!is_ok) {
+ fprintf(stderr, "Failed to allocate memory for roaring array. Bailing out.\n");
+ return false;
+ }
+
+ for (int32_t k = 0; k < size; ++k) {
+ uint16_t tmp;
+ memcpy(&tmp, keyscards + 2*k, sizeof(tmp));
+ answer->keys[k] = tmp;
+ }
+ if ((!hasrun) || (size >= NO_OFFSET_THRESHOLD)) {
+ *readbytes += size * 4;
+ if(*readbytes > maxbytes) {// data is corrupted?
+ fprintf(stderr, "Ran out of bytes while reading offsets.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+
+ // skipping the offsets
+ buf += size * 4;
+ }
+ // Reading the containers
+ for (int32_t k = 0; k < size; ++k) {
+ uint16_t tmp;
+ memcpy(&tmp, keyscards + 2*k+1, sizeof(tmp));
+ uint32_t thiscard = tmp + 1;
+ bool isbitmap = (thiscard > DEFAULT_MAX_SIZE);
+ bool isrun = false;
+ if(hasrun) {
+ if((bitmapOfRunContainers[k / 8] & (1 << (k % 8))) != 0) {
+ isbitmap = false;
+ isrun = true;
+ }
+ }
+ if (isbitmap) {
+ // we check that the read is allowed
+ size_t containersize = BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+ *readbytes += containersize;
+ if(*readbytes > maxbytes) {
+ fprintf(stderr, "Running out of bytes while reading a bitset container.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ // it is now safe to read
+ bitset_container_t *c = bitset_container_create();
+ if(c == NULL) {// memory allocation failure
+ fprintf(stderr, "Failed to allocate memory for a bitset container.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ answer->size++;
+ buf += bitset_container_read(thiscard, c, buf);
+ answer->containers[k] = c;
+ answer->typecodes[k] = BITSET_CONTAINER_TYPE_CODE;
+ } else if (isrun) {
+ // we check that the read is allowed
+ *readbytes += sizeof(uint16_t);
+ if(*readbytes > maxbytes) {
+ fprintf(stderr, "Running out of bytes while reading a run container (header).\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ uint16_t n_runs;
+ memcpy(&n_runs, buf, sizeof(uint16_t));
+ size_t containersize = n_runs * sizeof(rle16_t);
+ *readbytes += containersize;
+ if(*readbytes > maxbytes) {// data is corrupted?
+ fprintf(stderr, "Running out of bytes while reading a run container.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ // it is now safe to read
+
+ run_container_t *c = run_container_create();
+ if(c == NULL) {// memory allocation failure
+ fprintf(stderr, "Failed to allocate memory for a run container.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ answer->size++;
+ buf += run_container_read(thiscard, c, buf);
+ answer->containers[k] = c;
+ answer->typecodes[k] = RUN_CONTAINER_TYPE_CODE;
+ } else {
+ // we check that the read is allowed
+ size_t containersize = thiscard * sizeof(uint16_t);
+ *readbytes += containersize;
+ if(*readbytes > maxbytes) {// data is corrupted?
+ fprintf(stderr, "Running out of bytes while reading an array container.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ // it is now safe to read
+ array_container_t *c =
+ array_container_create_given_capacity(thiscard);
+ if(c == NULL) {// memory allocation failure
+ fprintf(stderr, "Failed to allocate memory for an array container.\n");
+ ra_clear(answer);// we need to clear the containers already allocated, and the roaring array
+ return false;
+ }
+ answer->size++;
+ buf += array_container_read(thiscard, c, buf);
+ answer->containers[k] = c;
+ answer->typecodes[k] = ARRAY_CONTAINER_TYPE_CODE;
+ }
+ }
+ return true;
+}
+/* end file src/roaring_array.c */
+/* begin file src/roaring_priority_queue.c */
+
+struct roaring_pq_element_s {
+ uint64_t size;
+ bool is_temporary;
+ roaring_bitmap_t *bitmap;
+};
+
+typedef struct roaring_pq_element_s roaring_pq_element_t;
+
+struct roaring_pq_s {
+ roaring_pq_element_t *elements;
+ uint64_t size;
+};
+
+typedef struct roaring_pq_s roaring_pq_t;
+
+static inline bool compare(roaring_pq_element_t *t1, roaring_pq_element_t *t2) {
+ return t1->size < t2->size;
+}
+
+static void pq_add(roaring_pq_t *pq, roaring_pq_element_t *t) {
+ uint64_t i = pq->size;
+ pq->elements[pq->size++] = *t;
+ while (i > 0) {
+ uint64_t p = (i - 1) >> 1;
+ roaring_pq_element_t ap = pq->elements[p];
+ if (!compare(t, &ap)) break;
+ pq->elements[i] = ap;
+ i = p;
+ }
+ pq->elements[i] = *t;
+}
+
+static void pq_free(roaring_pq_t *pq) {
+ free(pq->elements);
+ pq->elements = NULL; // paranoid
+ free(pq);
+}
+
+static void percolate_down(roaring_pq_t *pq, uint32_t i) {
+ uint32_t size = (uint32_t)pq->size;
+ uint32_t hsize = size >> 1;
+ roaring_pq_element_t ai = pq->elements[i];
+ while (i < hsize) {
+ uint32_t l = (i << 1) + 1;
+ uint32_t r = l + 1;
+ roaring_pq_element_t bestc = pq->elements[l];
+ if (r < size) {
+ if (compare(pq->elements + r, &bestc)) {
+ l = r;
+ bestc = pq->elements[r];
+ }
+ }
+ if (!compare(&bestc, &ai)) {
+ break;
+ }
+ pq->elements[i] = bestc;
+ i = l;
+ }
+ pq->elements[i] = ai;
+}
+
+static roaring_pq_t *create_pq(const roaring_bitmap_t **arr, uint32_t length) {
+ roaring_pq_t *answer = (roaring_pq_t *)malloc(sizeof(roaring_pq_t));
+ answer->elements =
+ (roaring_pq_element_t *)malloc(sizeof(roaring_pq_element_t) * length);
+ answer->size = length;
+ for (uint32_t i = 0; i < length; i++) {
+ answer->elements[i].bitmap = (roaring_bitmap_t *)arr[i];
+ answer->elements[i].is_temporary = false;
+ answer->elements[i].size =
+ roaring_bitmap_portable_size_in_bytes(arr[i]);
+ }
+ for (int32_t i = (length >> 1); i >= 0; i--) {
+ percolate_down(answer, i);
+ }
+ return answer;
+}
+
+static roaring_pq_element_t pq_poll(roaring_pq_t *pq) {
+ roaring_pq_element_t ans = *pq->elements;
+ if (pq->size > 1) {
+ pq->elements[0] = pq->elements[--pq->size];
+ percolate_down(pq, 0);
+ } else
+ --pq->size;
+ // memmove(pq->elements,pq->elements+1,(pq->size-1)*sizeof(roaring_pq_element_t));--pq->size;
+ return ans;
+}
+
+// this function consumes and frees the inputs
+static roaring_bitmap_t *lazy_or_from_lazy_inputs(roaring_bitmap_t *x1,
+ roaring_bitmap_t *x2) {
+ uint8_t container_result_type = 0;
+ const int length1 = ra_get_size(&x1->high_low_container),
+ length2 = ra_get_size(&x2->high_low_container);
+ if (0 == length1) {
+ roaring_bitmap_free(x1);
+ return x2;
+ }
+ if (0 == length2) {
+ roaring_bitmap_free(x2);
+ return x1;
+ }
+ uint32_t neededcap = length1 > length2 ? length2 : length1;
+ roaring_bitmap_t *answer = roaring_bitmap_create_with_capacity(neededcap);
+ int pos1 = 0, pos2 = 0;
+ uint8_t container_type_1, container_type_2;
+ uint16_t s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ uint16_t s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ while (true) {
+ if (s1 == s2) {
+ // todo: unsharing can be inefficient as it may create a clone where
+ // none
+ // is needed, but it has the benefit of being easy to reason about.
+ ra_unshare_container_at_index(&x1->high_low_container, pos1);
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ assert(container_type_1 != SHARED_CONTAINER_TYPE_CODE);
+ ra_unshare_container_at_index(&x2->high_low_container, pos2);
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ assert(container_type_2 != SHARED_CONTAINER_TYPE_CODE);
+ void *c;
+
+ if ((container_type_2 == BITSET_CONTAINER_TYPE_CODE) &&
+ (container_type_1 != BITSET_CONTAINER_TYPE_CODE)) {
+ c = container_lazy_ior(c2, container_type_2, c1,
+ container_type_1,
+ &container_result_type);
+ container_free(c1, container_type_1);
+ if (c != c2) {
+ container_free(c2, container_type_2);
+ }
+ } else {
+ c = container_lazy_ior(c1, container_type_1, c2,
+ container_type_2,
+ &container_result_type);
+ container_free(c2, container_type_2);
+ if (c != c1) {
+ container_free(c1, container_type_1);
+ }
+ }
+ // since we assume that the initial containers are non-empty, the
+ // result here
+ // can only be non-empty
+ ra_append(&answer->high_low_container, s1, c,
+ container_result_type);
+ ++pos1;
+ ++pos2;
+ if (pos1 == length1) break;
+ if (pos2 == length2) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+
+ } else if (s1 < s2) { // s1 < s2
+ void *c1 = ra_get_container_at_index(&x1->high_low_container, pos1,
+ &container_type_1);
+ ra_append(&answer->high_low_container, s1, c1, container_type_1);
+ pos1++;
+ if (pos1 == length1) break;
+ s1 = ra_get_key_at_index(&x1->high_low_container, pos1);
+
+ } else { // s1 > s2
+ void *c2 = ra_get_container_at_index(&x2->high_low_container, pos2,
+ &container_type_2);
+ ra_append(&answer->high_low_container, s2, c2, container_type_2);
+ pos2++;
+ if (pos2 == length2) break;
+ s2 = ra_get_key_at_index(&x2->high_low_container, pos2);
+ }
+ }
+ if (pos1 == length1) {
+ ra_append_move_range(&answer->high_low_container,
+ &x2->high_low_container, pos2, length2);
+ } else if (pos2 == length2) {
+ ra_append_move_range(&answer->high_low_container,
+ &x1->high_low_container, pos1, length1);
+ }
+ ra_clear_without_containers(&x1->high_low_container);
+ ra_clear_without_containers(&x2->high_low_container);
+ free(x1);
+ free(x2);
+ return answer;
+}
+
+/**
+ * Compute the union of 'number' bitmaps using a heap. This can
+ * sometimes be faster than roaring_bitmap_or_many which uses
+ * a naive algorithm. Caller is responsible for freeing the
+ * result.
+ */
+roaring_bitmap_t *roaring_bitmap_or_many_heap(uint32_t number,
+ const roaring_bitmap_t **x) {
+ if (number == 0) {
+ return roaring_bitmap_create();
+ }
+ if (number == 1) {
+ return roaring_bitmap_copy(x[0]);
+ }
+ roaring_pq_t *pq = create_pq(x, number);
+ while (pq->size > 1) {
+ roaring_pq_element_t x1 = pq_poll(pq);
+ roaring_pq_element_t x2 = pq_poll(pq);
+
+ if (x1.is_temporary && x2.is_temporary) {
+ roaring_bitmap_t *newb =
+ lazy_or_from_lazy_inputs(x1.bitmap, x2.bitmap);
+ // should normally return a fresh new bitmap *except* that
+ // it can return x1.bitmap or x2.bitmap in degenerate cases
+ bool temporary = !((newb == x1.bitmap) && (newb == x2.bitmap));
+ uint64_t bsize = roaring_bitmap_portable_size_in_bytes(newb);
+ roaring_pq_element_t newelement = {
+ .size = bsize, .is_temporary = temporary, .bitmap = newb};
+ pq_add(pq, &newelement);
+ } else if (x2.is_temporary) {
+ roaring_bitmap_lazy_or_inplace(x2.bitmap, x1.bitmap, false);
+ x2.size = roaring_bitmap_portable_size_in_bytes(x2.bitmap);
+ pq_add(pq, &x2);
+ } else if (x1.is_temporary) {
+ roaring_bitmap_lazy_or_inplace(x1.bitmap, x2.bitmap, false);
+ x1.size = roaring_bitmap_portable_size_in_bytes(x1.bitmap);
+
+ pq_add(pq, &x1);
+ } else {
+ roaring_bitmap_t *newb =
+ roaring_bitmap_lazy_or(x1.bitmap, x2.bitmap, false);
+ uint64_t bsize = roaring_bitmap_portable_size_in_bytes(newb);
+ roaring_pq_element_t newelement = {
+ .size = bsize, .is_temporary = true, .bitmap = newb};
+
+ pq_add(pq, &newelement);
+ }
+ }
+ roaring_pq_element_t X = pq_poll(pq);
+ roaring_bitmap_t *answer = X.bitmap;
+ roaring_bitmap_repair_after_lazy(answer);
+ pq_free(pq);
+ return answer;
+}
+/* end file src/roaring_priority_queue.c */
+
+#pragma GCC diagnostic pop
diff --git a/contrib/eggbitset/roaring.h b/contrib/eggbitset/roaring.h
new file mode 100644
index 00000000..1b5a5937
--- /dev/null
+++ b/contrib/eggbitset/roaring.h
@@ -0,0 +1,7090 @@
+/*
+ * Amalgamated copy of CRoaring 0.2.66, modified for GTK to reduce compiler
+ * warnings.
+ *
+ * Copyright 2016-2020 The CRoaring authors
+ * Copyright 2020 Benjamin Otte
+ *
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/* begin file include/roaring/roaring_version.h */
+// /include/roaring/roaring_version.h automatically generated by release.py, do not change by hand
+#ifndef ROARING_INCLUDE_ROARING_VERSION
+#define ROARING_INCLUDE_ROARING_VERSION
+#define ROARING_VERSION = 0.2.66,
+enum {
+ ROARING_VERSION_MAJOR = 0,
+ ROARING_VERSION_MINOR = 2,
+ ROARING_VERSION_REVISION = 66
+};
+#endif // ROARING_INCLUDE_ROARING_VERSION
+/* end file include/roaring/roaring_version.h */
+/* begin file include/roaring/portability.h */
+/*
+ * portability.h
+ *
+ */
+
+#ifndef INCLUDE_PORTABILITY_H_
+#define INCLUDE_PORTABILITY_H_
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+
+#if !(defined(_POSIX_C_SOURCE)) || (_POSIX_C_SOURCE < 200809L)
+#define _POSIX_C_SOURCE 200809L
+#endif
+#if !(defined(_XOPEN_SOURCE)) || (_XOPEN_SOURCE < 700)
+#define _XOPEN_SOURCE 700
+#endif
+
+#include
+#include
+#include // will provide posix_memalign with _POSIX_C_SOURCE as defined above
+#if !(defined(__APPLE__)) && !(defined(__FreeBSD__)) && !(defined(__OpenBSD__))
+#include // this should never be needed but there are some reports that it is needed.
+#endif
+
+
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(_WIN64) && !defined(ROARING_ACK_32BIT)
+#pragma message( \
+ "You appear to be attempting a 32-bit build under Visual Studio. We recommend a 64-bit build instead.")
+#endif
+
+#if defined(__SIZEOF_LONG_LONG__) && __SIZEOF_LONG_LONG__ != 8
+#error This code assumes 64-bit long longs (by use of the GCC intrinsics). Your system is not currently supported.
+#endif
+
+#if defined(_MSC_VER)
+#define __restrict__ __restrict
+#endif
+
+#ifndef DISABLE_X64 // some users may want to compile as if they did not have
+ // an x64 processor
+
+///////////////////////
+/// We support X64 hardware in the following manner:
+///
+/// if IS_X64 is defined then we have at least SSE and SSE2
+/// (All Intel processors sold in the recent past have at least SSE and SSE2 support,
+/// going back to the Pentium 4.)
+///
+/// if USESSE4 is defined then we assume at least SSE4.2, SSE4.1,
+/// SSSE3, SSE3... + IS_X64
+/// if USEAVX is defined, then we assume AVX2, AVX + USESSE4
+///
+/// So if you have hardware that supports AVX but not AVX2, then "USEAVX"
+/// won't be enabled.
+/// If you have hardware that supports SSE4.1, but not SSE4.2, then USESSE4
+/// won't be defined.
+//////////////////////
+
+// unless DISABLEAVX was defined, if we have __AVX2__, we enable AVX
+#if (!defined(USEAVX)) && (!defined(DISABLEAVX)) && (defined(__AVX2__))
+#define USEAVX
+#endif
+
+// if we have __SSE4_2__, we enable SSE4
+#if (defined(__POPCNT__)) && (defined(__SSE4_2__))
+#define USESSE4
+#endif
+
+#if defined(USEAVX) || defined(__x86_64__) || defined(_M_X64)
+// we have an x64 processor
+#define IS_X64
+// we include the intrinsic header
+#ifndef _MSC_VER
+/* Non-Microsoft C/C++-compatible compiler */
+#include // on some recent GCC, this will declare posix_memalign
+#endif
+#endif
+
+#if !defined(USENEON) && !defined(DISABLENEON) && defined(__ARM_NEON)
+# define USENEON
+#endif
+#if defined(USENEON)
+# include
+#endif
+
+#ifndef _MSC_VER
+/* Non-Microsoft C/C++-compatible compiler, assumes that it supports inline
+ * assembly */
+#define ROARING_INLINE_ASM
+#endif
+
+#ifdef USEAVX
+#define USESSE4 // if we have AVX, then we have SSE4
+#define USE_BMI // we assume that AVX2 and BMI go hand and hand
+#define USEAVX2FORDECODING // optimization
+// vector operations should work on not just AVX
+#define ROARING_VECTOR_OPERATIONS_ENABLED // vector unions (optimization)
+#endif
+
+#endif // DISABLE_X64
+
+#ifdef _MSC_VER
+/* Microsoft C/C++-compatible compiler */
+#include
+
+#ifndef __clang__ // if one compiles with MSVC *with* clang, then these
+ // intrinsics are defined!!!
+// sadly there is no way to check whether we are missing these intrinsics
+// specifically.
+
+/* wrappers for Visual Studio built-ins that look like gcc built-ins */
+/* result might be undefined when input_num is zero */
+static inline int __builtin_ctzll(unsigned long long input_num) {
+ unsigned long index;
+#ifdef _WIN64 // highly recommended!!!
+ _BitScanForward64(&index, input_num);
+#else // if we must support 32-bit Windows
+ if ((uint32_t)input_num != 0) {
+ _BitScanForward(&index, (uint32_t)input_num);
+ } else {
+ _BitScanForward(&index, (uint32_t)(input_num >> 32));
+ index += 32;
+ }
+#endif
+ return index;
+}
+
+/* result might be undefined when input_num is zero */
+static inline int __builtin_clzll(unsigned long long input_num) {
+ unsigned long index;
+#ifdef _WIN64 // highly recommended!!!
+ _BitScanReverse64(&index, input_num);
+#else // if we must support 32-bit Windows
+ if (input_num > 0xFFFFFFFF) {
+ _BitScanReverse(&index, (uint32_t)(input_num >> 32));
+ index += 32;
+ } else {
+ _BitScanReverse(&index, (uint32_t)(input_num));
+ }
+#endif
+ return 63 - index;
+}
+
+/* result might be undefined when input_num is zero */
+#ifdef USESSE4
+/* POPCNT support was added to processors around the release of SSE4.2 */
+/* USESSE4 flag guarantees POPCNT support */
+static inline int __builtin_popcountll(unsigned long long input_num) {
+#ifdef _WIN64 // highly recommended!!!
+ return (int)__popcnt64(input_num);
+#else // if we must support 32-bit Windows
+ return (int)(__popcnt((uint32_t)input_num) +
+ __popcnt((uint32_t)(input_num >> 32)));
+#endif
+}
+#else
+/* software implementation avoids POPCNT */
+static inline int __builtin_popcountll(unsigned long long input_num) {
+ const uint64_t m1 = 0x5555555555555555; //binary: 0101...
+ const uint64_t m2 = 0x3333333333333333; //binary: 00110011..
+ const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ...
+ const uint64_t h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
+
+ input_num -= (input_num >> 1) & m1;
+ input_num = (input_num & m2) + ((input_num >> 2) & m2);
+ input_num = (input_num + (input_num >> 4)) & m4;
+ return (input_num * h01) >> 56;
+}
+#endif
+
+/* Use #define so this is effective even under /Ob0 (no inline) */
+#define __builtin_unreachable() __assume(0)
+#endif
+
+#endif
+
+// portable version of posix_memalign
+static inline void *roaring_bitmap_aligned_malloc(size_t alignment, size_t size) {
+ void *p;
+#ifdef _MSC_VER
+ p = _aligned_malloc(size, alignment);
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+ p = __mingw_aligned_malloc(size, alignment);
+#else
+ // somehow, if this is used before including "x86intrin.h", it creates an
+ // implicit defined warning.
+ if (posix_memalign(&p, alignment, size) != 0) return NULL;
+#endif
+ return p;
+}
+
+static inline void roaring_bitmap_aligned_free(void *memblock) {
+#ifdef _MSC_VER
+ _aligned_free(memblock);
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+ __mingw_aligned_free(memblock);
+#else
+ free(memblock);
+#endif
+}
+
+#if defined(_MSC_VER)
+#define ALIGNED(x) __declspec(align(x))
+#else
+#if defined(__GNUC__)
+#define ALIGNED(x) __attribute__((aligned(x)))
+#endif
+#endif
+
+#ifdef __GNUC__
+#define WARN_UNUSED __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED
+#endif
+
+#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
+
+static inline int hamming(uint64_t x) {
+#ifdef USESSE4
+ return (int) _mm_popcnt_u64(x);
+#else
+ // won't work under visual studio, but hopeful we have _mm_popcnt_u64 in
+ // many cases
+ return __builtin_popcountll(x);
+#endif
+}
+
+#ifndef UINT64_C
+#define UINT64_C(c) (c##ULL)
+#endif
+
+#ifndef UINT32_C
+#define UINT32_C(c) (c##UL)
+#endif
+
+#endif /* INCLUDE_PORTABILITY_H_ */
+/* end file include/roaring/portability.h */
+/* begin file include/roaring/containers/perfparameters.h */
+#ifndef PERFPARAMETERS_H_
+#define PERFPARAMETERS_H_
+
+#include
+
+/**
+During lazy computations, we can transform array containers into bitset
+containers as
+long as we can expect them to have ARRAY_LAZY_LOWERBOUND values.
+*/
+enum { ARRAY_LAZY_LOWERBOUND = 1024 };
+
+/* default initial size of a run container
+ setting it to zero delays the malloc.*/
+enum { RUN_DEFAULT_INIT_SIZE = 0 };
+
+/* default initial size of an array container
+ setting it to zero delays the malloc */
+enum { ARRAY_DEFAULT_INIT_SIZE = 0 };
+
+/* automatic bitset conversion during lazy or */
+#ifndef LAZY_OR_BITSET_CONVERSION
+#define LAZY_OR_BITSET_CONVERSION true
+#endif
+
+/* automatically attempt to convert a bitset to a full run during lazy
+ * evaluation */
+#ifndef LAZY_OR_BITSET_CONVERSION_TO_FULL
+#define LAZY_OR_BITSET_CONVERSION_TO_FULL true
+#endif
+
+/* automatically attempt to convert a bitset to a full run */
+#ifndef OR_BITSET_CONVERSION_TO_FULL
+#define OR_BITSET_CONVERSION_TO_FULL true
+#endif
+
+#endif
+/* end file include/roaring/containers/perfparameters.h */
+/* begin file include/roaring/array_util.h */
+#ifndef ARRAY_UTIL_H
+#define ARRAY_UTIL_H
+
+#include // for size_t
+#include
+
+
+/*
+ * Good old binary search.
+ * Assumes that array is sorted, has logarithmic complexity.
+ * if the result is x, then:
+ * if ( x>0 ) you have array[x] = ikey
+ * if ( x<0 ) then inserting ikey at position -x-1 in array (insuring that array[-x-1]=ikey)
+ * keys the array sorted.
+ */
+static inline int32_t binarySearch(const uint16_t *array, int32_t lenarray,
+ uint16_t ikey) {
+ int32_t low = 0;
+ int32_t high = lenarray - 1;
+ while (low <= high) {
+ int32_t middleIndex = (low + high) >> 1;
+ uint16_t middleValue = array[middleIndex];
+ if (middleValue < ikey) {
+ low = middleIndex + 1;
+ } else if (middleValue > ikey) {
+ high = middleIndex - 1;
+ } else {
+ return middleIndex;
+ }
+ }
+ return -(low + 1);
+}
+
+/**
+ * Galloping search
+ * Assumes that array is sorted, has logarithmic complexity.
+ * if the result is x, then if x = length, you have that all values in array between pos and length
+ * are smaller than min.
+ * otherwise returns the first index x such that array[x] >= min.
+ */
+static inline int32_t advanceUntil(const uint16_t *array, int32_t pos,
+ int32_t length, uint16_t min) {
+ int32_t lower = pos + 1;
+
+ if ((lower >= length) || (array[lower] >= min)) {
+ return lower;
+ }
+
+ int32_t spansize = 1;
+
+ while ((lower + spansize < length) && (array[lower + spansize] < min)) {
+ spansize <<= 1;
+ }
+ int32_t upper = (lower + spansize < length) ? lower + spansize : length - 1;
+
+ if (array[upper] == min) {
+ return upper;
+ }
+ if (array[upper] < min) {
+ // means
+ // array
+ // has no
+ // item
+ // >= min
+ // pos = array.length;
+ return length;
+ }
+
+ // we know that the next-smallest span was too small
+ lower += (spansize >> 1);
+
+ int32_t mid = 0;
+ while (lower + 1 != upper) {
+ mid = (lower + upper) >> 1;
+ if (array[mid] == min) {
+ return mid;
+ } else if (array[mid] < min) {
+ lower = mid;
+ } else {
+ upper = mid;
+ }
+ }
+ return upper;
+}
+
+/**
+ * Returns number of elements which are less then $ikey.
+ * Array elements must be unique and sorted.
+ */
+static inline int32_t count_less(const uint16_t *array, int32_t lenarray,
+ uint16_t ikey) {
+ if (lenarray == 0) return 0;
+ int32_t pos = binarySearch(array, lenarray, ikey);
+ return pos >= 0 ? pos : -(pos+1);
+}
+
+/**
+ * Returns number of elements which are greater then $ikey.
+ * Array elements must be unique and sorted.
+ */
+static inline int32_t count_greater(const uint16_t *array, int32_t lenarray,
+ uint16_t ikey) {
+ if (lenarray == 0) return 0;
+ int32_t pos = binarySearch(array, lenarray, ikey);
+ if (pos >= 0) {
+ return lenarray - (pos+1);
+ } else {
+ return lenarray - (-pos-1);
+ }
+}
+
+/**
+ * From Schlegel et al., Fast Sorted-Set Intersection using SIMD Instructions
+ * Optimized by D. Lemire on May 3rd 2013
+ *
+ * C should have capacity greater than the minimum of s_1 and s_b + 8
+ * where 8 is sizeof(__m128i)/sizeof(uint16_t).
+ */
+int32_t intersect_vector16(const uint16_t *__restrict__ A, size_t s_a,
+ const uint16_t *__restrict__ B, size_t s_b,
+ uint16_t *C);
+
+/**
+ * Compute the cardinality of the intersection using SSE4 instructions
+ */
+int32_t intersect_vector16_cardinality(const uint16_t *__restrict__ A,
+ size_t s_a,
+ const uint16_t *__restrict__ B,
+ size_t s_b);
+
+/* Computes the intersection between one small and one large set of uint16_t.
+ * Stores the result into buffer and return the number of elements. */
+int32_t intersect_skewed_uint16(const uint16_t *smallarray, size_t size_s,
+ const uint16_t *largearray, size_t size_l,
+ uint16_t *buffer);
+
+/* Computes the size of the intersection between one small and one large set of
+ * uint16_t. */
+int32_t intersect_skewed_uint16_cardinality(const uint16_t *smallarray,
+ size_t size_s,
+ const uint16_t *largearray,
+ size_t size_l);
+
+
+/* Check whether the size of the intersection between one small and one large set of uint16_t is non-zero. */
+bool intersect_skewed_uint16_nonempty(const uint16_t *smallarray, size_t size_s,
+ const uint16_t *largearray, size_t size_l);
+/**
+ * Generic intersection function.
+ */
+int32_t intersect_uint16(const uint16_t *A, const size_t lenA,
+ const uint16_t *B, const size_t lenB, uint16_t *out);
+/**
+ * Compute the size of the intersection (generic).
+ */
+int32_t intersect_uint16_cardinality(const uint16_t *A, const size_t lenA,
+ const uint16_t *B, const size_t lenB);
+
+/**
+ * Checking whether the size of the intersection is non-zero.
+ */
+bool intersect_uint16_nonempty(const uint16_t *A, const size_t lenA,
+ const uint16_t *B, const size_t lenB);
+/**
+ * Generic union function.
+ */
+size_t union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
+ size_t size_2, uint16_t *buffer);
+
+/**
+ * Generic XOR function.
+ */
+int32_t xor_uint16(const uint16_t *array_1, int32_t card_1,
+ const uint16_t *array_2, int32_t card_2, uint16_t *out);
+
+/**
+ * Generic difference function (ANDNOT).
+ */
+int difference_uint16(const uint16_t *a1, int length1, const uint16_t *a2,
+ int length2, uint16_t *a_out);
+
+/**
+ * Generic intersection function.
+ */
+size_t intersection_uint32(const uint32_t *A, const size_t lenA,
+ const uint32_t *B, const size_t lenB, uint32_t *out);
+
+/**
+ * Generic intersection function, returns just the cardinality.
+ */
+size_t intersection_uint32_card(const uint32_t *A, const size_t lenA,
+ const uint32_t *B, const size_t lenB);
+
+/**
+ * Generic union function.
+ */
+size_t union_uint32(const uint32_t *set_1, size_t size_1, const uint32_t *set_2,
+ size_t size_2, uint32_t *buffer);
+
+/**
+ * A fast SSE-based union function.
+ */
+uint32_t union_vector16(const uint16_t *__restrict__ set_1, uint32_t size_1,
+ const uint16_t *__restrict__ set_2, uint32_t size_2,
+ uint16_t *__restrict__ buffer);
+/**
+ * A fast SSE-based XOR function.
+ */
+uint32_t xor_vector16(const uint16_t *__restrict__ array1, uint32_t length1,
+ const uint16_t *__restrict__ array2, uint32_t length2,
+ uint16_t *__restrict__ output);
+
+/**
+ * A fast SSE-based difference function.
+ */
+int32_t difference_vector16(const uint16_t *__restrict__ A, size_t s_a,
+ const uint16_t *__restrict__ B, size_t s_b,
+ uint16_t *C);
+
+/**
+ * Generic union function, returns just the cardinality.
+ */
+size_t union_uint32_card(const uint32_t *set_1, size_t size_1,
+ const uint32_t *set_2, size_t size_2);
+
+/**
+* combines union_uint16 and union_vector16 optimally
+*/
+size_t fast_union_uint16(const uint16_t *set_1, size_t size_1, const uint16_t *set_2,
+ size_t size_2, uint16_t *buffer);
+
+
+bool memequals(const void *s1, const void *s2, size_t n);
+
+#endif
+/* end file include/roaring/array_util.h */
+/* begin file include/roaring/roaring_types.h */
+/*
+ Typedefs used by various components
+*/
+
+#ifndef ROARING_TYPES_H
+#define ROARING_TYPES_H
+
+typedef bool (*roaring_iterator)(uint32_t value, void *param);
+typedef bool (*roaring_iterator64)(uint64_t value, void *param);
+
+/**
+* (For advanced users.)
+* The roaring_statistics_t can be used to collect detailed statistics about
+* the composition of a roaring bitmap.
+*/
+typedef struct roaring_statistics_s {
+ uint32_t n_containers; /* number of containers */
+
+ uint32_t n_array_containers; /* number of array containers */
+ uint32_t n_run_containers; /* number of run containers */
+ uint32_t n_bitset_containers; /* number of bitmap containers */
+
+ uint32_t
+ n_values_array_containers; /* number of values in array containers */
+ uint32_t n_values_run_containers; /* number of values in run containers */
+ uint32_t
+ n_values_bitset_containers; /* number of values in bitmap containers */
+
+ uint32_t n_bytes_array_containers; /* number of allocated bytes in array
+ containers */
+ uint32_t n_bytes_run_containers; /* number of allocated bytes in run
+ containers */
+ uint32_t n_bytes_bitset_containers; /* number of allocated bytes in bitmap
+ containers */
+
+ uint32_t
+ max_value; /* the maximal value, undefined if cardinality is zero */
+ uint32_t
+ min_value; /* the minimal value, undefined if cardinality is zero */
+ uint64_t sum_value; /* the sum of all values (could be used to compute
+ average) */
+
+ uint64_t cardinality; /* total number of values stored in the bitmap */
+
+ // and n_values_arrays, n_values_rle, n_values_bitmap
+} roaring_statistics_t;
+
+#endif /* ROARING_TYPES_H */
+/* end file include/roaring/roaring_types.h */
+/* begin file include/roaring/utilasm.h */
+/*
+ * utilasm.h
+ *
+ */
+
+#ifndef INCLUDE_UTILASM_H_
+#define INCLUDE_UTILASM_H_
+
+
+#if defined(USE_BMI) & defined(ROARING_INLINE_ASM)
+#define ASMBITMANIPOPTIMIZATION // optimization flag
+
+#define ASM_SHIFT_RIGHT(srcReg, bitsReg, destReg) \
+ __asm volatile("shrx %1, %2, %0" \
+ : "=r"(destReg) \
+ : /* write */ \
+ "r"(bitsReg), /* read only */ \
+ "r"(srcReg) /* read only */ \
+ )
+
+#define ASM_INPLACESHIFT_RIGHT(srcReg, bitsReg) \
+ __asm volatile("shrx %1, %0, %0" \
+ : "+r"(srcReg) \
+ : /* read/write */ \
+ "r"(bitsReg) /* read only */ \
+ )
+
+#define ASM_SHIFT_LEFT(srcReg, bitsReg, destReg) \
+ __asm volatile("shlx %1, %2, %0" \
+ : "=r"(destReg) \
+ : /* write */ \
+ "r"(bitsReg), /* read only */ \
+ "r"(srcReg) /* read only */ \
+ )
+// set bit at position testBit within testByte to 1 and
+// copy cmovDst to cmovSrc if that bit was previously clear
+#define ASM_SET_BIT_INC_WAS_CLEAR(testByte, testBit, count) \
+ __asm volatile( \
+ "bts %2, %0\n" \
+ "sbb $-1, %1\n" \
+ : "+r"(testByte), /* read/write */ \
+ "+r"(count) \
+ : /* read/write */ \
+ "r"(testBit) /* read only */ \
+ )
+
+#define ASM_CLEAR_BIT_DEC_WAS_SET(testByte, testBit, count) \
+ __asm volatile( \
+ "btr %2, %0\n" \
+ "sbb $0, %1\n" \
+ : "+r"(testByte), /* read/write */ \
+ "+r"(count) \
+ : /* read/write */ \
+ "r"(testBit) /* read only */ \
+ )
+
+#define ASM_BT64(testByte, testBit, count) \
+ __asm volatile( \
+ "bt %2,%1\n" \
+ "sbb %0,%0" /*could use setb */ \
+ : "=r"(count) \
+ : /* write */ \
+ "r"(testByte), /* read only */ \
+ "r"(testBit) /* read only */ \
+ )
+
+#endif // USE_BMI
+#endif /* INCLUDE_UTILASM_H_ */
+/* end file include/roaring/utilasm.h */
+/* begin file include/roaring/bitset_util.h */
+#ifndef BITSET_UTIL_H
+#define BITSET_UTIL_H
+
+#include
+
+
+/*
+ * Set all bits in indexes [begin,end) to true.
+ */
+static inline void bitset_set_range(uint64_t *bitmap, uint32_t start,
+ uint32_t end) {
+ if (start == end) return;
+ uint32_t firstword = start / 64;
+ uint32_t endword = (end - 1) / 64;
+ if (firstword == endword) {
+ bitmap[firstword] |= ((~UINT64_C(0)) << (start % 64)) &
+ ((~UINT64_C(0)) >> ((~end + 1) % 64));
+ return;
+ }
+ bitmap[firstword] |= (~UINT64_C(0)) << (start % 64);
+ for (uint32_t i = firstword + 1; i < endword; i++) bitmap[i] = ~UINT64_C(0);
+ bitmap[endword] |= (~UINT64_C(0)) >> ((~end + 1) % 64);
+}
+
+
+/*
+ * Find the cardinality of the bitset in [begin,begin+lenminusone]
+ */
+static inline int bitset_lenrange_cardinality(uint64_t *bitmap, uint32_t start,
+ uint32_t lenminusone) {
+ uint32_t firstword = start / 64;
+ uint32_t endword = (start + lenminusone) / 64;
+ if (firstword == endword) {
+ return hamming(bitmap[firstword] &
+ ((~UINT64_C(0)) >> ((63 - lenminusone) % 64))
+ << (start % 64));
+ }
+ int answer = hamming(bitmap[firstword] & ((~UINT64_C(0)) << (start % 64)));
+ for (uint32_t i = firstword + 1; i < endword; i++) {
+ answer += hamming(bitmap[i]);
+ }
+ answer +=
+ hamming(bitmap[endword] &
+ (~UINT64_C(0)) >> (((~start + 1) - lenminusone - 1) % 64));
+ return answer;
+}
+
+/*
+ * Check whether the cardinality of the bitset in [begin,begin+lenminusone] is 0
+ */
+static inline bool bitset_lenrange_empty(uint64_t *bitmap, uint32_t start,
+ uint32_t lenminusone) {
+ uint32_t firstword = start / 64;
+ uint32_t endword = (start + lenminusone) / 64;
+ if (firstword == endword) {
+ return (bitmap[firstword] & ((~UINT64_C(0)) >> ((63 - lenminusone) % 64))
+ << (start % 64)) == 0;
+ }
+ if(((bitmap[firstword] & ((~UINT64_C(0)) << (start%64)))) != 0) return false;
+ for (uint32_t i = firstword + 1; i < endword; i++) {
+ if(bitmap[i] != 0) return false;
+ }
+ if((bitmap[endword] & (~UINT64_C(0)) >> (((~start + 1) - lenminusone - 1) % 64)) != 0) return false;
+ return true;
+}
+
+
+/*
+ * Set all bits in indexes [begin,begin+lenminusone] to true.
+ */
+static inline void bitset_set_lenrange(uint64_t *bitmap, uint32_t start,
+ uint32_t lenminusone) {
+ uint32_t firstword = start / 64;
+ uint32_t endword = (start + lenminusone) / 64;
+ if (firstword == endword) {
+ bitmap[firstword] |= ((~UINT64_C(0)) >> ((63 - lenminusone) % 64))
+ << (start % 64);
+ return;
+ }
+ uint64_t temp = bitmap[endword];
+ bitmap[firstword] |= (~UINT64_C(0)) << (start % 64);
+ for (uint32_t i = firstword + 1; i < endword; i += 2)
+ bitmap[i] = bitmap[i + 1] = ~UINT64_C(0);
+ bitmap[endword] =
+ temp | (~UINT64_C(0)) >> (((~start + 1) - lenminusone - 1) % 64);
+}
+
+/*
+ * Flip all the bits in indexes [begin,end).
+ */
+static inline void bitset_flip_range(uint64_t *bitmap, uint32_t start,
+ uint32_t end) {
+ if (start == end) return;
+ uint32_t firstword = start / 64;
+ uint32_t endword = (end - 1) / 64;
+ bitmap[firstword] ^= ~((~UINT64_C(0)) << (start % 64));
+ for (uint32_t i = firstword; i < endword; i++) bitmap[i] = ~bitmap[i];
+ bitmap[endword] ^= ((~UINT64_C(0)) >> ((~end + 1) % 64));
+}
+
+/*
+ * Set all bits in indexes [begin,end) to false.
+ */
+static inline void bitset_reset_range(uint64_t *bitmap, uint32_t start,
+ uint32_t end) {
+ if (start == end) return;
+ uint32_t firstword = start / 64;
+ uint32_t endword = (end - 1) / 64;
+ if (firstword == endword) {
+ bitmap[firstword] &= ~(((~UINT64_C(0)) << (start % 64)) &
+ ((~UINT64_C(0)) >> ((~end + 1) % 64)));
+ return;
+ }
+ bitmap[firstword] &= ~((~UINT64_C(0)) << (start % 64));
+ for (uint32_t i = firstword + 1; i < endword; i++) bitmap[i] = UINT64_C(0);
+ bitmap[endword] &= ~((~UINT64_C(0)) >> ((~end + 1) % 64));
+}
+
+/*
+ * Given a bitset containing "length" 64-bit words, write out the position
+ * of all the set bits to "out", values start at "base".
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ * set.
+ *
+ * Returns how many values were actually decoded.
+ *
+ * This function should only be expected to be faster than
+ * bitset_extract_setbits
+ * when the density of the bitset is high.
+ *
+ * This function uses AVX2 decoding.
+ */
+size_t bitset_extract_setbits_avx2(uint64_t *bitset, size_t length, void *vout,
+ size_t outcapacity, uint32_t base);
+
+/*
+ * Given a bitset containing "length" 64-bit words, write out the position
+ * of all the set bits to "out", values start at "base".
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ *set.
+ *
+ * Returns how many values were actually decoded.
+ */
+size_t bitset_extract_setbits(uint64_t *bitset, size_t length, void *vout,
+ uint32_t base);
+
+/*
+ * Given a bitset containing "length" 64-bit words, write out the position
+ * of all the set bits to "out" as 16-bit integers, values start at "base" (can
+ *be set to zero)
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ *set.
+ *
+ * Returns how many values were actually decoded.
+ *
+ * This function should only be expected to be faster than
+ *bitset_extract_setbits_uint16
+ * when the density of the bitset is high.
+ *
+ * This function uses SSE decoding.
+ */
+size_t bitset_extract_setbits_sse_uint16(const uint64_t *bitset, size_t length,
+ uint16_t *out, size_t outcapacity,
+ uint16_t base);
+
+/*
+ * Given a bitset containing "length" 64-bit words, write out the position
+ * of all the set bits to "out", values start at "base"
+ * (can be set to zero)
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ *set.
+ *
+ * Returns how many values were actually decoded.
+ */
+size_t bitset_extract_setbits_uint16(const uint64_t *bitset, size_t length,
+ uint16_t *out, uint16_t base);
+
+/*
+ * Given two bitsets containing "length" 64-bit words, write out the position
+ * of all the common set bits to "out", values start at "base"
+ * (can be set to zero)
+ *
+ * The "out" pointer should be sufficient to store the actual number of bits
+ * set.
+ *
+ * Returns how many values were actually decoded.
+ */
+size_t bitset_extract_intersection_setbits_uint16(const uint64_t * __restrict__ bitset1,
+ const uint64_t * __restrict__ bitset2,
+ size_t length, uint16_t *out,
+ uint16_t base);
+
+/*
+ * Given a bitset having cardinality card, set all bit values in the list (there
+ * are length of them)
+ * and return the updated cardinality. This evidently assumes that the bitset
+ * already contained data.
+ */
+uint64_t bitset_set_list_withcard(void *bitset, uint64_t card,
+ const uint16_t *list, uint64_t length);
+/*
+ * Given a bitset, set all bit values in the list (there
+ * are length of them).
+ */
+void bitset_set_list(void *bitset, const uint16_t *list, uint64_t length);
+
+/*
+ * Given a bitset having cardinality card, unset all bit values in the list
+ * (there are length of them)
+ * and return the updated cardinality. This evidently assumes that the bitset
+ * already contained data.
+ */
+uint64_t bitset_clear_list(void *bitset, uint64_t card, const uint16_t *list,
+ uint64_t length);
+
+/*
+ * Given a bitset having cardinality card, toggle all bit values in the list
+ * (there are length of them)
+ * and return the updated cardinality. This evidently assumes that the bitset
+ * already contained data.
+ */
+
+uint64_t bitset_flip_list_withcard(void *bitset, uint64_t card,
+ const uint16_t *list, uint64_t length);
+
+void bitset_flip_list(void *bitset, const uint16_t *list, uint64_t length);
+
+#ifdef USEAVX
+/***
+ * BEGIN Harley-Seal popcount functions.
+ */
+
+/**
+ * Compute the population count of a 256-bit word
+ * This is not especially fast, but it is convenient as part of other functions.
+ */
+static inline __m256i popcount256(__m256i v) {
+ const __m256i lookuppos = _mm256_setr_epi8(
+ /* 0 */ 4 + 0, /* 1 */ 4 + 1, /* 2 */ 4 + 1, /* 3 */ 4 + 2,
+ /* 4 */ 4 + 1, /* 5 */ 4 + 2, /* 6 */ 4 + 2, /* 7 */ 4 + 3,
+ /* 8 */ 4 + 1, /* 9 */ 4 + 2, /* a */ 4 + 2, /* b */ 4 + 3,
+ /* c */ 4 + 2, /* d */ 4 + 3, /* e */ 4 + 3, /* f */ 4 + 4,
+
+ /* 0 */ 4 + 0, /* 1 */ 4 + 1, /* 2 */ 4 + 1, /* 3 */ 4 + 2,
+ /* 4 */ 4 + 1, /* 5 */ 4 + 2, /* 6 */ 4 + 2, /* 7 */ 4 + 3,
+ /* 8 */ 4 + 1, /* 9 */ 4 + 2, /* a */ 4 + 2, /* b */ 4 + 3,
+ /* c */ 4 + 2, /* d */ 4 + 3, /* e */ 4 + 3, /* f */ 4 + 4);
+ const __m256i lookupneg = _mm256_setr_epi8(
+ /* 0 */ 4 - 0, /* 1 */ 4 - 1, /* 2 */ 4 - 1, /* 3 */ 4 - 2,
+ /* 4 */ 4 - 1, /* 5 */ 4 - 2, /* 6 */ 4 - 2, /* 7 */ 4 - 3,
+ /* 8 */ 4 - 1, /* 9 */ 4 - 2, /* a */ 4 - 2, /* b */ 4 - 3,
+ /* c */ 4 - 2, /* d */ 4 - 3, /* e */ 4 - 3, /* f */ 4 - 4,
+
+ /* 0 */ 4 - 0, /* 1 */ 4 - 1, /* 2 */ 4 - 1, /* 3 */ 4 - 2,
+ /* 4 */ 4 - 1, /* 5 */ 4 - 2, /* 6 */ 4 - 2, /* 7 */ 4 - 3,
+ /* 8 */ 4 - 1, /* 9 */ 4 - 2, /* a */ 4 - 2, /* b */ 4 - 3,
+ /* c */ 4 - 2, /* d */ 4 - 3, /* e */ 4 - 3, /* f */ 4 - 4);
+ const __m256i low_mask = _mm256_set1_epi8(0x0f);
+
+ const __m256i lo = _mm256_and_si256(v, low_mask);
+ const __m256i hi = _mm256_and_si256(_mm256_srli_epi16(v, 4), low_mask);
+ const __m256i popcnt1 = _mm256_shuffle_epi8(lookuppos, lo);
+ const __m256i popcnt2 = _mm256_shuffle_epi8(lookupneg, hi);
+ return _mm256_sad_epu8(popcnt1, popcnt2);
+}
+
+/**
+ * Simple CSA over 256 bits
+ */
+static inline void CSA(__m256i *h, __m256i *l, __m256i a, __m256i b,
+ __m256i c) {
+ const __m256i u = _mm256_xor_si256(a, b);
+ *h = _mm256_or_si256(_mm256_and_si256(a, b), _mm256_and_si256(u, c));
+ *l = _mm256_xor_si256(u, c);
+}
+
+/**
+ * Fast Harley-Seal AVX population count function
+ */
+inline static uint64_t avx2_harley_seal_popcount256(const __m256i *data,
+ const uint64_t size) {
+ __m256i total = _mm256_setzero_si256();
+ __m256i ones = _mm256_setzero_si256();
+ __m256i twos = _mm256_setzero_si256();
+ __m256i fours = _mm256_setzero_si256();
+ __m256i eights = _mm256_setzero_si256();
+ __m256i sixteens = _mm256_setzero_si256();
+ __m256i twosA, twosB, foursA, foursB, eightsA, eightsB;
+
+ const uint64_t limit = size - size % 16;
+ uint64_t i = 0;
+
+ for (; i < limit; i += 16) {
+ CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i),
+ _mm256_lddqu_si256(data + i + 1));
+ CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 2),
+ _mm256_lddqu_si256(data + i + 3));
+ CSA(&foursA, &twos, twos, twosA, twosB);
+ CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i + 4),
+ _mm256_lddqu_si256(data + i + 5));
+ CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 6),
+ _mm256_lddqu_si256(data + i + 7));
+ CSA(&foursB, &twos, twos, twosA, twosB);
+ CSA(&eightsA, &fours, fours, foursA, foursB);
+ CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i + 8),
+ _mm256_lddqu_si256(data + i + 9));
+ CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 10),
+ _mm256_lddqu_si256(data + i + 11));
+ CSA(&foursA, &twos, twos, twosA, twosB);
+ CSA(&twosA, &ones, ones, _mm256_lddqu_si256(data + i + 12),
+ _mm256_lddqu_si256(data + i + 13));
+ CSA(&twosB, &ones, ones, _mm256_lddqu_si256(data + i + 14),
+ _mm256_lddqu_si256(data + i + 15));
+ CSA(&foursB, &twos, twos, twosA, twosB);
+ CSA(&eightsB, &fours, fours, foursA, foursB);
+ CSA(&sixteens, &eights, eights, eightsA, eightsB);
+
+ total = _mm256_add_epi64(total, popcount256(sixteens));
+ }
+
+ total = _mm256_slli_epi64(total, 4); // * 16
+ total = _mm256_add_epi64(
+ total, _mm256_slli_epi64(popcount256(eights), 3)); // += 8 * ...
+ total = _mm256_add_epi64(
+ total, _mm256_slli_epi64(popcount256(fours), 2)); // += 4 * ...
+ total = _mm256_add_epi64(
+ total, _mm256_slli_epi64(popcount256(twos), 1)); // += 2 * ...
+ total = _mm256_add_epi64(total, popcount256(ones));
+ for (; i < size; i++)
+ total =
+ _mm256_add_epi64(total, popcount256(_mm256_lddqu_si256(data + i)));
+
+ return (uint64_t)(_mm256_extract_epi64(total, 0)) +
+ (uint64_t)(_mm256_extract_epi64(total, 1)) +
+ (uint64_t)(_mm256_extract_epi64(total, 2)) +
+ (uint64_t)(_mm256_extract_epi64(total, 3));
+}
+
+#define AVXPOPCNTFNC(opname, avx_intrinsic) \
+ static inline uint64_t avx2_harley_seal_popcount256_##opname( \
+ const __m256i *data1, const __m256i *data2, const uint64_t size) { \
+ __m256i total = _mm256_setzero_si256(); \
+ __m256i ones = _mm256_setzero_si256(); \
+ __m256i twos = _mm256_setzero_si256(); \
+ __m256i fours = _mm256_setzero_si256(); \
+ __m256i eights = _mm256_setzero_si256(); \
+ __m256i sixteens = _mm256_setzero_si256(); \
+ __m256i twosA, twosB, foursA, foursB, eightsA, eightsB; \
+ __m256i A1, A2; \
+ const uint64_t limit = size - size % 16; \
+ uint64_t i = 0; \
+ for (; i < limit; i += 16) { \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
+ _mm256_lddqu_si256(data2 + i)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 1), \
+ _mm256_lddqu_si256(data2 + i + 1)); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 2), \
+ _mm256_lddqu_si256(data2 + i + 2)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 3), \
+ _mm256_lddqu_si256(data2 + i + 3)); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursA, &twos, twos, twosA, twosB); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 4), \
+ _mm256_lddqu_si256(data2 + i + 4)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 5), \
+ _mm256_lddqu_si256(data2 + i + 5)); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 6), \
+ _mm256_lddqu_si256(data2 + i + 6)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 7), \
+ _mm256_lddqu_si256(data2 + i + 7)); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursB, &twos, twos, twosA, twosB); \
+ CSA(&eightsA, &fours, fours, foursA, foursB); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 8), \
+ _mm256_lddqu_si256(data2 + i + 8)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 9), \
+ _mm256_lddqu_si256(data2 + i + 9)); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 10), \
+ _mm256_lddqu_si256(data2 + i + 10)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 11), \
+ _mm256_lddqu_si256(data2 + i + 11)); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursA, &twos, twos, twosA, twosB); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 12), \
+ _mm256_lddqu_si256(data2 + i + 12)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 13), \
+ _mm256_lddqu_si256(data2 + i + 13)); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 14), \
+ _mm256_lddqu_si256(data2 + i + 14)); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 15), \
+ _mm256_lddqu_si256(data2 + i + 15)); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursB, &twos, twos, twosA, twosB); \
+ CSA(&eightsB, &fours, fours, foursA, foursB); \
+ CSA(&sixteens, &eights, eights, eightsA, eightsB); \
+ total = _mm256_add_epi64(total, popcount256(sixteens)); \
+ } \
+ total = _mm256_slli_epi64(total, 4); \
+ total = _mm256_add_epi64(total, \
+ _mm256_slli_epi64(popcount256(eights), 3)); \
+ total = \
+ _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(fours), 2)); \
+ total = \
+ _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(twos), 1)); \
+ total = _mm256_add_epi64(total, popcount256(ones)); \
+ for (; i < size; i++) { \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
+ _mm256_lddqu_si256(data2 + i)); \
+ total = _mm256_add_epi64(total, popcount256(A1)); \
+ } \
+ return (uint64_t)(_mm256_extract_epi64(total, 0)) + \
+ (uint64_t)(_mm256_extract_epi64(total, 1)) + \
+ (uint64_t)(_mm256_extract_epi64(total, 2)) + \
+ (uint64_t)(_mm256_extract_epi64(total, 3)); \
+ } \
+ static inline uint64_t avx2_harley_seal_popcount256andstore_##opname( \
+ const __m256i *__restrict__ data1, const __m256i *__restrict__ data2, \
+ __m256i *__restrict__ out, const uint64_t size) { \
+ __m256i total = _mm256_setzero_si256(); \
+ __m256i ones = _mm256_setzero_si256(); \
+ __m256i twos = _mm256_setzero_si256(); \
+ __m256i fours = _mm256_setzero_si256(); \
+ __m256i eights = _mm256_setzero_si256(); \
+ __m256i sixteens = _mm256_setzero_si256(); \
+ __m256i twosA, twosB, foursA, foursB, eightsA, eightsB; \
+ __m256i A1, A2; \
+ const uint64_t limit = size - size % 16; \
+ uint64_t i = 0; \
+ for (; i < limit; i += 16) { \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
+ _mm256_lddqu_si256(data2 + i)); \
+ _mm256_storeu_si256(out + i, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 1), \
+ _mm256_lddqu_si256(data2 + i + 1)); \
+ _mm256_storeu_si256(out + i + 1, A2); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 2), \
+ _mm256_lddqu_si256(data2 + i + 2)); \
+ _mm256_storeu_si256(out + i + 2, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 3), \
+ _mm256_lddqu_si256(data2 + i + 3)); \
+ _mm256_storeu_si256(out + i + 3, A2); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursA, &twos, twos, twosA, twosB); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 4), \
+ _mm256_lddqu_si256(data2 + i + 4)); \
+ _mm256_storeu_si256(out + i + 4, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 5), \
+ _mm256_lddqu_si256(data2 + i + 5)); \
+ _mm256_storeu_si256(out + i + 5, A2); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 6), \
+ _mm256_lddqu_si256(data2 + i + 6)); \
+ _mm256_storeu_si256(out + i + 6, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 7), \
+ _mm256_lddqu_si256(data2 + i + 7)); \
+ _mm256_storeu_si256(out + i + 7, A2); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursB, &twos, twos, twosA, twosB); \
+ CSA(&eightsA, &fours, fours, foursA, foursB); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 8), \
+ _mm256_lddqu_si256(data2 + i + 8)); \
+ _mm256_storeu_si256(out + i + 8, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 9), \
+ _mm256_lddqu_si256(data2 + i + 9)); \
+ _mm256_storeu_si256(out + i + 9, A2); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 10), \
+ _mm256_lddqu_si256(data2 + i + 10)); \
+ _mm256_storeu_si256(out + i + 10, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 11), \
+ _mm256_lddqu_si256(data2 + i + 11)); \
+ _mm256_storeu_si256(out + i + 11, A2); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursA, &twos, twos, twosA, twosB); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 12), \
+ _mm256_lddqu_si256(data2 + i + 12)); \
+ _mm256_storeu_si256(out + i + 12, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 13), \
+ _mm256_lddqu_si256(data2 + i + 13)); \
+ _mm256_storeu_si256(out + i + 13, A2); \
+ CSA(&twosA, &ones, ones, A1, A2); \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 14), \
+ _mm256_lddqu_si256(data2 + i + 14)); \
+ _mm256_storeu_si256(out + i + 14, A1); \
+ A2 = avx_intrinsic(_mm256_lddqu_si256(data1 + i + 15), \
+ _mm256_lddqu_si256(data2 + i + 15)); \
+ _mm256_storeu_si256(out + i + 15, A2); \
+ CSA(&twosB, &ones, ones, A1, A2); \
+ CSA(&foursB, &twos, twos, twosA, twosB); \
+ CSA(&eightsB, &fours, fours, foursA, foursB); \
+ CSA(&sixteens, &eights, eights, eightsA, eightsB); \
+ total = _mm256_add_epi64(total, popcount256(sixteens)); \
+ } \
+ total = _mm256_slli_epi64(total, 4); \
+ total = _mm256_add_epi64(total, \
+ _mm256_slli_epi64(popcount256(eights), 3)); \
+ total = \
+ _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(fours), 2)); \
+ total = \
+ _mm256_add_epi64(total, _mm256_slli_epi64(popcount256(twos), 1)); \
+ total = _mm256_add_epi64(total, popcount256(ones)); \
+ for (; i < size; i++) { \
+ A1 = avx_intrinsic(_mm256_lddqu_si256(data1 + i), \
+ _mm256_lddqu_si256(data2 + i)); \
+ _mm256_storeu_si256(out + i, A1); \
+ total = _mm256_add_epi64(total, popcount256(A1)); \
+ } \
+ return (uint64_t)(_mm256_extract_epi64(total, 0)) + \
+ (uint64_t)(_mm256_extract_epi64(total, 1)) + \
+ (uint64_t)(_mm256_extract_epi64(total, 2)) + \
+ (uint64_t)(_mm256_extract_epi64(total, 3)); \
+ }
+
+AVXPOPCNTFNC(or, _mm256_or_si256)
+AVXPOPCNTFNC(union, _mm256_or_si256)
+AVXPOPCNTFNC(and, _mm256_and_si256)
+AVXPOPCNTFNC(intersection, _mm256_and_si256)
+AVXPOPCNTFNC (xor, _mm256_xor_si256)
+AVXPOPCNTFNC(andnot, _mm256_andnot_si256)
+
+/***
+ * END Harley-Seal popcount functions.
+ */
+
+#endif // USEAVX
+
+#endif
+/* end file include/roaring/bitset_util.h */
+/* begin file include/roaring/containers/array.h */
+/*
+ * array.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_ARRAY_H_
+#define INCLUDE_CONTAINERS_ARRAY_H_
+
+#include
+
+
+/* Containers with DEFAULT_MAX_SIZE or less integers should be arrays */
+enum { DEFAULT_MAX_SIZE = 4096 };
+
+/* struct array_container - sparse representation of a bitmap
+ *
+ * @cardinality: number of indices in `array` (and the bitmap)
+ * @capacity: allocated size of `array`
+ * @array: sorted list of integers
+ */
+struct array_container_s {
+ int32_t cardinality;
+ int32_t capacity;
+ uint16_t *array;
+};
+
+typedef struct array_container_s array_container_t;
+
+/* Create a new array with default. Return NULL in case of failure. See also
+ * array_container_create_given_capacity. */
+array_container_t *array_container_create(void);
+
+/* Create a new array with a specified capacity size. Return NULL in case of
+ * failure. */
+array_container_t *array_container_create_given_capacity(int32_t size);
+
+/* Create a new array containing all values in [min,max). */
+array_container_t * array_container_create_range(uint32_t min, uint32_t max);
+
+/*
+ * Shrink the capacity to the actual size, return the number of bytes saved.
+ */
+int array_container_shrink_to_fit(array_container_t *src);
+
+/* Free memory owned by `array'. */
+void array_container_free(array_container_t *array);
+
+/* Duplicate container */
+array_container_t *array_container_clone(const array_container_t *src);
+
+int32_t array_container_serialize(const array_container_t *container,
+ char *buf) WARN_UNUSED;
+
+uint32_t array_container_serialization_len(const array_container_t *container);
+
+void *array_container_deserialize(const char *buf, size_t buf_len);
+
+/* Get the cardinality of `array'. */
+static inline int array_container_cardinality(const array_container_t *array) {
+ return array->cardinality;
+}
+
+static inline bool array_container_nonzero_cardinality(
+ const array_container_t *array) {
+ return array->cardinality > 0;
+}
+
+/* Copy one container into another. We assume that they are distinct. */
+void array_container_copy(const array_container_t *src, array_container_t *dst);
+
+/* Add all the values in [min,max) (included) at a distance k*step from min.
+ The container must have a size less or equal to DEFAULT_MAX_SIZE after this
+ addition. */
+void array_container_add_from_range(array_container_t *arr, uint32_t min,
+ uint32_t max, uint16_t step);
+
+/* Set the cardinality to zero (does not release memory). */
+static inline void array_container_clear(array_container_t *array) {
+ array->cardinality = 0;
+}
+
+static inline bool array_container_empty(const array_container_t *array) {
+ return array->cardinality == 0;
+}
+
+/* check whether the cardinality is equal to the capacity (this does not mean
+* that it contains 1<<16 elements) */
+static inline bool array_container_full(const array_container_t *array) {
+ return array->cardinality == array->capacity;
+}
+
+
+/* Compute the union of `src_1' and `src_2' and write the result to `dst'
+ * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
+void array_container_union(const array_container_t *src_1,
+ const array_container_t *src_2,
+ array_container_t *dst);
+
+/* symmetric difference, see array_container_union */
+void array_container_xor(const array_container_t *array_1,
+ const array_container_t *array_2,
+ array_container_t *out);
+
+/* Computes the intersection of src_1 and src_2 and write the result to
+ * dst. It is assumed that dst is distinct from both src_1 and src_2. */
+void array_container_intersection(const array_container_t *src_1,
+ const array_container_t *src_2,
+ array_container_t *dst);
+
+/* Check whether src_1 and src_2 intersect. */
+bool array_container_intersect(const array_container_t *src_1,
+ const array_container_t *src_2);
+
+
+/* computers the size of the intersection between two arrays.
+ */
+int array_container_intersection_cardinality(const array_container_t *src_1,
+ const array_container_t *src_2);
+
+/* computes the intersection of array1 and array2 and write the result to
+ * array1.
+ * */
+void array_container_intersection_inplace(array_container_t *src_1,
+ const array_container_t *src_2);
+
+/*
+ * Write out the 16-bit integers contained in this container as a list of 32-bit
+ * integers using base
+ * as the starting value (it might be expected that base has zeros in its 16
+ * least significant bits).
+ * The function returns the number of values written.
+ * The caller is responsible for allocating enough memory in out.
+ */
+int array_container_to_uint32_array(void *vout, const array_container_t *cont,
+ uint32_t base);
+
+/* Compute the number of runs */
+int32_t array_container_number_of_runs(const array_container_t *a);
+
+/*
+ * Print this container using printf (useful for debugging).
+ */
+void array_container_printf(const array_container_t *v);
+
+/*
+ * Print this container using printf as a comma-separated list of 32-bit
+ * integers starting at base.
+ */
+void array_container_printf_as_uint32_array(const array_container_t *v,
+ uint32_t base);
+
+/**
+ * Return the serialized size in bytes of a container having cardinality "card".
+ */
+static inline int32_t array_container_serialized_size_in_bytes(int32_t card) {
+ return card * 2 + 2;
+}
+
+/**
+ * Increase capacity to at least min.
+ * Whether the existing data needs to be copied over depends on the "preserve"
+ * parameter. If preserve is false, then the new content will be uninitialized,
+ * otherwise the old content is copied.
+ */
+void array_container_grow(array_container_t *container, int32_t min,
+ bool preserve);
+
+bool array_container_iterate(const array_container_t *cont, uint32_t base,
+ roaring_iterator iterator, void *ptr);
+bool array_container_iterate64(const array_container_t *cont, uint32_t base,
+ roaring_iterator64 iterator, uint64_t high_bits,
+ void *ptr);
+
+/**
+ * Writes the underlying array to buf, outputs how many bytes were written.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes written should be
+ * array_container_size_in_bytes(container).
+ *
+ */
+int32_t array_container_write(const array_container_t *container, char *buf);
+/**
+ * Reads the instance from buf, outputs how many bytes were read.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes read should be array_container_size_in_bytes(container).
+ * You need to provide the (known) cardinality.
+ */
+int32_t array_container_read(int32_t cardinality, array_container_t *container,
+ const char *buf);
+
+/**
+ * Return the serialized size in bytes of a container (see
+ * bitset_container_write)
+ * This is meant to be compatible with the Java and Go versions of Roaring and
+ * assumes
+ * that the cardinality of the container is already known.
+ *
+ */
+static inline int32_t array_container_size_in_bytes(
+ const array_container_t *container) {
+ return container->cardinality * sizeof(uint16_t);
+}
+
+/**
+ * Return true if the two arrays have the same content.
+ */
+static inline bool array_container_equals(
+ const array_container_t *container1,
+ const array_container_t *container2) {
+
+ if (container1->cardinality != container2->cardinality) {
+ return false;
+ }
+ return memequals(container1->array, container2->array, container1->cardinality*2);
+}
+
+/**
+ * Return true if container1 is a subset of container2.
+ */
+bool array_container_is_subset(const array_container_t *container1,
+ const array_container_t *container2);
+
+/**
+ * If the element of given rank is in this container, supposing that the first
+ * element has rank start_rank, then the function returns true and sets element
+ * accordingly.
+ * Otherwise, it returns false and update start_rank.
+ */
+static inline bool array_container_select(const array_container_t *container,
+ uint32_t *start_rank, uint32_t rank,
+ uint32_t *element) {
+ int card = array_container_cardinality(container);
+ if (*start_rank + card <= rank) {
+ *start_rank += card;
+ return false;
+ } else {
+ *element = container->array[rank - *start_rank];
+ return true;
+ }
+}
+
+/* Computes the difference of array1 and array2 and write the result
+ * to array out.
+ * Array out does not need to be distinct from array_1
+ */
+void array_container_andnot(const array_container_t *array_1,
+ const array_container_t *array_2,
+ array_container_t *out);
+
+/* Append x to the set. Assumes that the value is larger than any preceding
+ * values. */
+static inline void array_container_append(array_container_t *arr,
+ uint16_t pos) {
+ const int32_t capacity = arr->capacity;
+
+ if (array_container_full(arr)) {
+ array_container_grow(arr, capacity + 1, true);
+ }
+
+ arr->array[arr->cardinality++] = pos;
+}
+
+/**
+ * Add value to the set if final cardinality doesn't exceed max_cardinality.
+ * Return code:
+ * 1 -- value was added
+ * 0 -- value was already present
+ * -1 -- value was not added because cardinality would exceed max_cardinality
+ */
+static inline int array_container_try_add(array_container_t *arr, uint16_t value,
+ int32_t max_cardinality) {
+ const int32_t cardinality = arr->cardinality;
+
+ // best case, we can append.
+ if ((array_container_empty(arr) || arr->array[cardinality - 1] < value) &&
+ cardinality < max_cardinality) {
+ array_container_append(arr, value);
+ return 1;
+ }
+
+ const int32_t loc = binarySearch(arr->array, cardinality, value);
+
+ if (loc >= 0) {
+ return 0;
+ } else if (cardinality < max_cardinality) {
+ if (array_container_full(arr)) {
+ array_container_grow(arr, arr->capacity + 1, true);
+ }
+ const int32_t insert_idx = -loc - 1;
+ memmove(arr->array + insert_idx + 1, arr->array + insert_idx,
+ (cardinality - insert_idx) * sizeof(uint16_t));
+ arr->array[insert_idx] = value;
+ arr->cardinality++;
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+/* Add value to the set. Returns true if x was not already present. */
+static inline bool array_container_add(array_container_t *arr, uint16_t value) {
+ return array_container_try_add(arr, value, INT32_MAX) == 1;
+}
+
+/* Remove x from the set. Returns true if x was present. */
+static inline bool array_container_remove(array_container_t *arr,
+ uint16_t pos) {
+ const int32_t idx = binarySearch(arr->array, arr->cardinality, pos);
+ const bool is_present = idx >= 0;
+ if (is_present) {
+ memmove(arr->array + idx, arr->array + idx + 1,
+ (arr->cardinality - idx - 1) * sizeof(uint16_t));
+ arr->cardinality--;
+ }
+
+ return is_present;
+}
+
+/* Check whether x is present. */
+static inline bool array_container_contains(const array_container_t *arr,
+ uint16_t pos) {
+ // return binarySearch(arr->array, arr->cardinality, pos) >= 0;
+ // binary search with fallback to linear search for short ranges
+ int32_t low = 0;
+ const uint16_t * carr = (const uint16_t *) arr->array;
+ int32_t high = arr->cardinality - 1;
+ // while (high - low >= 0) {
+ while(high >= low + 16) {
+ int32_t middleIndex = (low + high)>>1;
+ uint16_t middleValue = carr[middleIndex];
+ if (middleValue < pos) {
+ low = middleIndex + 1;
+ } else if (middleValue > pos) {
+ high = middleIndex - 1;
+ } else {
+ return true;
+ }
+ }
+
+ for (int i=low; i <= high; i++) {
+ uint16_t v = carr[i];
+ if (v == pos) {
+ return true;
+ }
+ if ( v > pos ) return false;
+ }
+ return false;
+
+}
+
+//* Check whether a range of values from range_start (included) to range_end (excluded) is present. */
+static inline bool array_container_contains_range(const array_container_t *arr,
+ uint32_t range_start, uint32_t range_end) {
+
+ const uint16_t rs_included = range_start;
+ const uint16_t re_included = range_end - 1;
+
+ const uint16_t *carr = (const uint16_t *) arr->array;
+
+ const int32_t start = advanceUntil(carr, -1, arr->cardinality, rs_included);
+ const int32_t end = advanceUntil(carr, start - 1, arr->cardinality, re_included);
+
+ return (start < arr->cardinality) && (end < arr->cardinality)
+ && (((uint16_t)(end - start)) == re_included - rs_included)
+ && (carr[start] == rs_included) && (carr[end] == re_included);
+}
+
+/* Returns the smallest value (assumes not empty) */
+static inline uint16_t array_container_minimum(const array_container_t *arr) {
+ if (arr->cardinality == 0) return 0;
+ return arr->array[0];
+}
+
+/* Returns the largest value (assumes not empty) */
+static inline uint16_t array_container_maximum(const array_container_t *arr) {
+ if (arr->cardinality == 0) return 0;
+ return arr->array[arr->cardinality - 1];
+}
+
+/* Returns the number of values equal or smaller than x */
+static inline int array_container_rank(const array_container_t *arr, uint16_t x) {
+ const int32_t idx = binarySearch(arr->array, arr->cardinality, x);
+ const bool is_present = idx >= 0;
+ if (is_present) {
+ return idx + 1;
+ } else {
+ return -idx - 1;
+ }
+}
+
+/* Returns the index of the first value equal or smaller than x, or -1 */
+static inline int array_container_index_equalorlarger(const array_container_t *arr, uint16_t x) {
+ const int32_t idx = binarySearch(arr->array, arr->cardinality, x);
+ const bool is_present = idx >= 0;
+ if (is_present) {
+ return idx;
+ } else {
+ int32_t candidate = - idx - 1;
+ if(candidate < arr->cardinality) return candidate;
+ return -1;
+ }
+}
+
+/*
+ * Adds all values in range [min,max] using hint:
+ * nvals_less is the number of array values less than $min
+ * nvals_greater is the number of array values greater than $max
+ */
+static inline void array_container_add_range_nvals(array_container_t *array,
+ uint32_t min, uint32_t max,
+ int32_t nvals_less,
+ int32_t nvals_greater) {
+ int32_t union_cardinality = nvals_less + (max - min + 1) + nvals_greater;
+ if (union_cardinality > array->capacity) {
+ array_container_grow(array, union_cardinality, true);
+ }
+ memmove(&(array->array[union_cardinality - nvals_greater]),
+ &(array->array[array->cardinality - nvals_greater]),
+ nvals_greater * sizeof(uint16_t));
+ for (uint32_t i = 0; i <= max - min; i++) {
+ array->array[nvals_less + i] = min + i;
+ }
+ array->cardinality = union_cardinality;
+}
+
+/**
+ * Adds all values in range [min,max].
+ */
+static inline void array_container_add_range(array_container_t *array,
+ uint32_t min, uint32_t max) {
+ int32_t nvals_greater = count_greater(array->array, array->cardinality, max);
+ int32_t nvals_less = count_less(array->array, array->cardinality - nvals_greater, min);
+ array_container_add_range_nvals(array, min, max, nvals_less, nvals_greater);
+}
+
+/*
+ * Removes all elements array[pos] .. array[pos+count-1]
+ */
+static inline void array_container_remove_range(array_container_t *array,
+ uint32_t pos, uint32_t count) {
+ if (count != 0) {
+ memmove(&(array->array[pos]), &(array->array[pos+count]),
+ (array->cardinality - pos - count) * sizeof(uint16_t));
+ array->cardinality -= count;
+ }
+}
+
+#endif /* INCLUDE_CONTAINERS_ARRAY_H_ */
+/* end file include/roaring/containers/array.h */
+/* begin file include/roaring/containers/bitset.h */
+/*
+ * bitset.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_BITSET_H_
+#define INCLUDE_CONTAINERS_BITSET_H_
+
+#include
+#include
+
+#ifdef USEAVX
+#define ALIGN_AVX __attribute__((aligned(sizeof(__m256i))))
+#else
+#define ALIGN_AVX
+#endif
+
+enum {
+ BITSET_CONTAINER_SIZE_IN_WORDS = (1 << 16) / 64,
+ BITSET_UNKNOWN_CARDINALITY = -1
+};
+
+struct bitset_container_s {
+ int32_t cardinality;
+ uint64_t *array;
+};
+
+typedef struct bitset_container_s bitset_container_t;
+
+/* Create a new bitset. Return NULL in case of failure. */
+bitset_container_t *bitset_container_create(void);
+
+/* Free memory. */
+void bitset_container_free(bitset_container_t *bitset);
+
+/* Clear bitset (sets bits to 0). */
+void bitset_container_clear(bitset_container_t *bitset);
+
+/* Set all bits to 1. */
+void bitset_container_set_all(bitset_container_t *bitset);
+
+/* Duplicate bitset */
+bitset_container_t *bitset_container_clone(const bitset_container_t *src);
+
+int32_t bitset_container_serialize(const bitset_container_t *container,
+ char *buf) WARN_UNUSED;
+
+uint32_t bitset_container_serialization_len(void);
+
+void *bitset_container_deserialize(const char *buf, size_t buf_len);
+
+/* Set the bit in [begin,end). WARNING: as of April 2016, this method is slow
+ * and
+ * should not be used in performance-sensitive code. Ever. */
+void bitset_container_set_range(bitset_container_t *bitset, uint32_t begin,
+ uint32_t end);
+
+#ifdef ASMBITMANIPOPTIMIZATION
+/* Set the ith bit. */
+static inline void bitset_container_set(bitset_container_t *bitset,
+ uint16_t pos) {
+ uint64_t shift = 6;
+ uint64_t offset;
+ uint64_t p = pos;
+ ASM_SHIFT_RIGHT(p, shift, offset);
+ uint64_t load = bitset->array[offset];
+ ASM_SET_BIT_INC_WAS_CLEAR(load, p, bitset->cardinality);
+ bitset->array[offset] = load;
+}
+
+/* Unset the ith bit. */
+static inline void bitset_container_unset(bitset_container_t *bitset,
+ uint16_t pos) {
+ uint64_t shift = 6;
+ uint64_t offset;
+ uint64_t p = pos;
+ ASM_SHIFT_RIGHT(p, shift, offset);
+ uint64_t load = bitset->array[offset];
+ ASM_CLEAR_BIT_DEC_WAS_SET(load, p, bitset->cardinality);
+ bitset->array[offset] = load;
+}
+
+/* Add `pos' to `bitset'. Returns true if `pos' was not present. Might be slower
+ * than bitset_container_set. */
+static inline bool bitset_container_add(bitset_container_t *bitset,
+ uint16_t pos) {
+ uint64_t shift = 6;
+ uint64_t offset;
+ uint64_t p = pos;
+ ASM_SHIFT_RIGHT(p, shift, offset);
+ uint64_t load = bitset->array[offset];
+ // could be possibly slightly further optimized
+ const int32_t oldcard = bitset->cardinality;
+ ASM_SET_BIT_INC_WAS_CLEAR(load, p, bitset->cardinality);
+ bitset->array[offset] = load;
+ return bitset->cardinality - oldcard;
+}
+
+/* Remove `pos' from `bitset'. Returns true if `pos' was present. Might be
+ * slower than bitset_container_unset. */
+static inline bool bitset_container_remove(bitset_container_t *bitset,
+ uint16_t pos) {
+ uint64_t shift = 6;
+ uint64_t offset;
+ uint64_t p = pos;
+ ASM_SHIFT_RIGHT(p, shift, offset);
+ uint64_t load = bitset->array[offset];
+ // could be possibly slightly further optimized
+ const int32_t oldcard = bitset->cardinality;
+ ASM_CLEAR_BIT_DEC_WAS_SET(load, p, bitset->cardinality);
+ bitset->array[offset] = load;
+ return oldcard - bitset->cardinality;
+}
+
+/* Get the value of the ith bit. */
+static inline bool bitset_container_get(const bitset_container_t *bitset,
+ uint16_t pos) {
+ uint64_t word = bitset->array[pos >> 6];
+ const uint64_t p = pos;
+ ASM_INPLACESHIFT_RIGHT(word, p);
+ return word & 1;
+}
+
+#else
+
+/* Set the ith bit. */
+static inline void bitset_container_set(bitset_container_t *bitset,
+ uint16_t pos) {
+ const uint64_t old_word = bitset->array[pos >> 6];
+ const int index = pos & 63;
+ const uint64_t new_word = old_word | (UINT64_C(1) << index);
+ bitset->cardinality += (uint32_t)((old_word ^ new_word) >> index);
+ bitset->array[pos >> 6] = new_word;
+}
+
+/* Unset the ith bit. */
+static inline void bitset_container_unset(bitset_container_t *bitset,
+ uint16_t pos) {
+ const uint64_t old_word = bitset->array[pos >> 6];
+ const int index = pos & 63;
+ const uint64_t new_word = old_word & (~(UINT64_C(1) << index));
+ bitset->cardinality -= (uint32_t)((old_word ^ new_word) >> index);
+ bitset->array[pos >> 6] = new_word;
+}
+
+/* Add `pos' to `bitset'. Returns true if `pos' was not present. Might be slower
+ * than bitset_container_set. */
+static inline bool bitset_container_add(bitset_container_t *bitset,
+ uint16_t pos) {
+ const uint64_t old_word = bitset->array[pos >> 6];
+ const int index = pos & 63;
+ const uint64_t new_word = old_word | (UINT64_C(1) << index);
+ const uint64_t increment = (old_word ^ new_word) >> index;
+ bitset->cardinality += (uint32_t)increment;
+ bitset->array[pos >> 6] = new_word;
+ return increment > 0;
+}
+
+/* Remove `pos' from `bitset'. Returns true if `pos' was present. Might be
+ * slower than bitset_container_unset. */
+static inline bool bitset_container_remove(bitset_container_t *bitset,
+ uint16_t pos) {
+ const uint64_t old_word = bitset->array[pos >> 6];
+ const int index = pos & 63;
+ const uint64_t new_word = old_word & (~(UINT64_C(1) << index));
+ const uint64_t increment = (old_word ^ new_word) >> index;
+ bitset->cardinality -= (uint32_t)increment;
+ bitset->array[pos >> 6] = new_word;
+ return increment > 0;
+}
+
+/* Get the value of the ith bit. */
+static inline bool bitset_container_get(const bitset_container_t *bitset,
+ uint16_t pos) {
+ const uint64_t word = bitset->array[pos >> 6];
+ return (word >> (pos & 63)) & 1;
+}
+
+#endif
+
+/*
+* Check if all bits are set in a range of positions from pos_start (included) to
+* pos_end (excluded).
+*/
+static inline bool bitset_container_get_range(const bitset_container_t *bitset,
+ uint32_t pos_start, uint32_t pos_end) {
+
+ const uint32_t start = pos_start >> 6;
+ const uint32_t end = pos_end >> 6;
+
+ const uint64_t first = ~((1ULL << (pos_start & 0x3F)) - 1);
+ const uint64_t last = (1ULL << (pos_end & 0x3F)) - 1;
+
+ if (start == end) return ((bitset->array[end] & first & last) == (first & last));
+ if ((bitset->array[start] & first) != first) return false;
+
+ if ((end < BITSET_CONTAINER_SIZE_IN_WORDS) && ((bitset->array[end] & last) != last)){
+
+ return false;
+ }
+
+ for (uint16_t i = start + 1; (i < BITSET_CONTAINER_SIZE_IN_WORDS) && (i < end); ++i){
+
+ if (bitset->array[i] != UINT64_C(0xFFFFFFFFFFFFFFFF)) return false;
+ }
+
+ return true;
+}
+
+/* Check whether `bitset' is present in `array'. Calls bitset_container_get. */
+static inline bool bitset_container_contains(const bitset_container_t *bitset,
+ uint16_t pos) {
+ return bitset_container_get(bitset, pos);
+}
+
+/*
+* Check whether a range of bits from position `pos_start' (included) to `pos_end' (excluded)
+* is present in `bitset'. Calls bitset_container_get_all.
+*/
+static inline bool bitset_container_contains_range(const bitset_container_t *bitset,
+ uint32_t pos_start, uint32_t pos_end) {
+ return bitset_container_get_range(bitset, pos_start, pos_end);
+}
+
+/* Get the number of bits set */
+static inline int bitset_container_cardinality(
+ const bitset_container_t *bitset) {
+ return bitset->cardinality;
+}
+
+
+
+
+/* Copy one container into another. We assume that they are distinct. */
+void bitset_container_copy(const bitset_container_t *source,
+ bitset_container_t *dest);
+
+/* Add all the values [min,max) at a distance k*step from min: min,
+ * min+step,.... */
+void bitset_container_add_from_range(bitset_container_t *bitset, uint32_t min,
+ uint32_t max, uint16_t step);
+
+/* Get the number of bits set (force computation). This does not modify bitset.
+ * To update the cardinality, you should do
+ * bitset->cardinality = bitset_container_compute_cardinality(bitset).*/
+int bitset_container_compute_cardinality(const bitset_container_t *bitset);
+
+/* Get whether there is at least one bit set (see bitset_container_empty for the reverse),
+ when the cardinality is unknown, it is computed and stored in the struct */
+static inline bool bitset_container_nonzero_cardinality(
+ bitset_container_t *bitset) {
+ // account for laziness
+ if (bitset->cardinality == BITSET_UNKNOWN_CARDINALITY) {
+ // could bail early instead with a nonzero result
+ bitset->cardinality = bitset_container_compute_cardinality(bitset);
+ }
+ return bitset->cardinality > 0;
+}
+
+/* Check whether this bitset is empty (see bitset_container_nonzero_cardinality for the reverse),
+ * it never modifies the bitset struct. */
+static inline bool bitset_container_empty(
+ const bitset_container_t *bitset) {
+ if (bitset->cardinality == BITSET_UNKNOWN_CARDINALITY) {
+ for (int i = 0; i < BITSET_CONTAINER_SIZE_IN_WORDS; i ++) {
+ if((bitset->array[i]) != 0) return false;
+ }
+ return true;
+ }
+ return bitset->cardinality == 0;
+}
+
+
+/* Get whether there is at least one bit set (see bitset_container_empty for the reverse),
+ the bitset is never modified */
+static inline bool bitset_container_const_nonzero_cardinality(
+ const bitset_container_t *bitset) {
+ return !bitset_container_empty(bitset);
+}
+
+/*
+ * Check whether the two bitsets intersect
+ */
+bool bitset_container_intersect(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the union of bitsets `src_1' and `src_2' into `dst' and return the
+ * cardinality. */
+int bitset_container_or(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the union of bitsets `src_1' and `src_2' and return the cardinality.
+ */
+int bitset_container_or_justcard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the union of bitsets `src_1' and `src_2' into `dst' and return the
+ * cardinality. Same as bitset_container_or. */
+int bitset_container_union(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the union of bitsets `src_1' and `src_2' and return the
+ * cardinality. Same as bitset_container_or_justcard. */
+int bitset_container_union_justcard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the union of bitsets `src_1' and `src_2' into `dst', but does not
+ * update the cardinality. Provided to optimize chained operations. */
+int bitset_container_or_nocard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the union of bitsets `src_1' and `src_2' into `dst', but does not
+ * update the cardinality. Same as bitset_container_or_nocard */
+int bitset_container_union_nocard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the intersection of bitsets `src_1' and `src_2' into `dst' and
+ * return the cardinality. */
+int bitset_container_and(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the intersection of bitsets `src_1' and `src_2' and return the
+ * cardinality. */
+int bitset_container_and_justcard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the intersection of bitsets `src_1' and `src_2' into `dst' and
+ * return the cardinality. Same as bitset_container_and. */
+int bitset_container_intersection(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the intersection of bitsets `src_1' and `src_2' and return the
+ * cardinality. Same as bitset_container_and_justcard. */
+int bitset_container_intersection_justcard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the intersection of bitsets `src_1' and `src_2' into `dst', but does
+ * not update the cardinality. Provided to optimize chained operations. */
+int bitset_container_and_nocard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the intersection of bitsets `src_1' and `src_2' into `dst', but does
+ * not update the cardinality. Same as bitset_container_and_nocard */
+int bitset_container_intersection_nocard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the exclusive or of bitsets `src_1' and `src_2' into `dst' and
+ * return the cardinality. */
+int bitset_container_xor(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the exclusive or of bitsets `src_1' and `src_2' and return the
+ * cardinality. */
+int bitset_container_xor_justcard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the exclusive or of bitsets `src_1' and `src_2' into `dst', but does
+ * not update the cardinality. Provided to optimize chained operations. */
+int bitset_container_xor_nocard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the and not of bitsets `src_1' and `src_2' into `dst' and return the
+ * cardinality. */
+int bitset_container_andnot(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Computes the and not of bitsets `src_1' and `src_2' and return the
+ * cardinality. */
+int bitset_container_andnot_justcard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Computes the and not or of bitsets `src_1' and `src_2' into `dst', but does
+ * not update the cardinality. Provided to optimize chained operations. */
+int bitset_container_andnot_nocard(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/*
+ * Write out the 16-bit integers contained in this container as a list of 32-bit
+ * integers using base
+ * as the starting value (it might be expected that base has zeros in its 16
+ * least significant bits).
+ * The function returns the number of values written.
+ * The caller is responsible for allocating enough memory in out.
+ * The out pointer should point to enough memory (the cardinality times 32
+ * bits).
+ */
+int bitset_container_to_uint32_array(void *out, const bitset_container_t *cont,
+ uint32_t base);
+
+/*
+ * Print this container using printf (useful for debugging).
+ */
+void bitset_container_printf(const bitset_container_t *v);
+
+/*
+ * Print this container using printf as a comma-separated list of 32-bit
+ * integers starting at base.
+ */
+void bitset_container_printf_as_uint32_array(const bitset_container_t *v,
+ uint32_t base);
+
+/**
+ * Return the serialized size in bytes of a container.
+ */
+static inline int32_t bitset_container_serialized_size_in_bytes(void) {
+ return BITSET_CONTAINER_SIZE_IN_WORDS * 8;
+}
+
+/**
+ * Return the the number of runs.
+ */
+int bitset_container_number_of_runs(bitset_container_t *b);
+
+bool bitset_container_iterate(const bitset_container_t *cont, uint32_t base,
+ roaring_iterator iterator, void *ptr);
+bool bitset_container_iterate64(const bitset_container_t *cont, uint32_t base,
+ roaring_iterator64 iterator, uint64_t high_bits,
+ void *ptr);
+
+/**
+ * Writes the underlying array to buf, outputs how many bytes were written.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes written should be
+ * bitset_container_size_in_bytes(container).
+ */
+int32_t bitset_container_write(const bitset_container_t *container, char *buf);
+
+/**
+ * Reads the instance from buf, outputs how many bytes were read.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes read should be bitset_container_size_in_bytes(container).
+ * You need to provide the (known) cardinality.
+ */
+int32_t bitset_container_read(int32_t cardinality,
+ bitset_container_t *container, const char *buf);
+/**
+ * Return the serialized size in bytes of a container (see
+ * bitset_container_write).
+ * This is meant to be compatible with the Java and Go versions of Roaring and
+ * assumes
+ * that the cardinality of the container is already known or can be computed.
+ */
+static inline int32_t bitset_container_size_in_bytes(
+ const bitset_container_t *container) {
+ (void)container;
+ return BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+}
+
+/**
+ * Return true if the two containers have the same content.
+ */
+bool bitset_container_equals(const bitset_container_t *container1,
+ const bitset_container_t *container2);
+
+/**
+* Return true if container1 is a subset of container2.
+*/
+bool bitset_container_is_subset(const bitset_container_t *container1,
+ const bitset_container_t *container2);
+
+/**
+ * If the element of given rank is in this container, supposing that the first
+ * element has rank start_rank, then the function returns true and sets element
+ * accordingly.
+ * Otherwise, it returns false and update start_rank.
+ */
+bool bitset_container_select(const bitset_container_t *container,
+ uint32_t *start_rank, uint32_t rank,
+ uint32_t *element);
+
+/* Returns the smallest value (assumes not empty) */
+uint16_t bitset_container_minimum(const bitset_container_t *container);
+
+/* Returns the largest value (assumes not empty) */
+uint16_t bitset_container_maximum(const bitset_container_t *container);
+
+/* Returns the number of values equal or smaller than x */
+int bitset_container_rank(const bitset_container_t *container, uint16_t x);
+
+/* Returns the index of the first value equal or larger than x, or -1 */
+int bitset_container_index_equalorlarger(const bitset_container_t *container, uint16_t x);
+#endif /* INCLUDE_CONTAINERS_BITSET_H_ */
+/* end file include/roaring/containers/bitset.h */
+/* begin file include/roaring/containers/run.h */
+/*
+ * run.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_RUN_H_
+#define INCLUDE_CONTAINERS_RUN_H_
+
+#include
+#include
+#include
+#include
+
+
+/* struct rle16_s - run length pair
+ *
+ * @value: start position of the run
+ * @length: length of the run is `length + 1`
+ *
+ * An RLE pair {v, l} would represent the integers between the interval
+ * [v, v+l+1], e.g. {3, 2} = [3, 4, 5].
+ */
+struct rle16_s {
+ uint16_t value;
+ uint16_t length;
+};
+
+typedef struct rle16_s rle16_t;
+
+/* struct run_container_s - run container bitmap
+ *
+ * @n_runs: number of rle_t pairs in `runs`.
+ * @capacity: capacity in rle_t pairs `runs` can hold.
+ * @runs: pairs of rle_t.
+ *
+ */
+struct run_container_s {
+ int32_t n_runs;
+ int32_t capacity;
+ rle16_t *runs;
+};
+
+typedef struct run_container_s run_container_t;
+
+/* Create a new run container. Return NULL in case of failure. */
+run_container_t *run_container_create(void);
+
+/* Create a new run container with given capacity. Return NULL in case of
+ * failure. */
+run_container_t *run_container_create_given_capacity(int32_t size);
+
+/*
+ * Shrink the capacity to the actual size, return the number of bytes saved.
+ */
+int run_container_shrink_to_fit(run_container_t *src);
+
+/* Free memory owned by `run'. */
+void run_container_free(run_container_t *run);
+
+/* Duplicate container */
+run_container_t *run_container_clone(const run_container_t *src);
+
+int32_t run_container_serialize(const run_container_t *container,
+ char *buf) WARN_UNUSED;
+
+uint32_t run_container_serialization_len(const run_container_t *container);
+
+void *run_container_deserialize(const char *buf, size_t buf_len);
+
+/*
+ * Effectively deletes the value at index index, repacking data.
+ */
+static inline void recoverRoomAtIndex(run_container_t *run, uint16_t index) {
+ memmove(run->runs + index, run->runs + (1 + index),
+ (run->n_runs - index - 1) * sizeof(rle16_t));
+ run->n_runs--;
+}
+
+/**
+ * Good old binary search through rle data
+ */
+static inline int32_t interleavedBinarySearch(const rle16_t *array, int32_t lenarray,
+ uint16_t ikey) {
+ int32_t low = 0;
+ int32_t high = lenarray - 1;
+ while (low <= high) {
+ int32_t middleIndex = (low + high) >> 1;
+ uint16_t middleValue = array[middleIndex].value;
+ if (middleValue < ikey) {
+ low = middleIndex + 1;
+ } else if (middleValue > ikey) {
+ high = middleIndex - 1;
+ } else {
+ return middleIndex;
+ }
+ }
+ return -(low + 1);
+}
+
+/*
+ * Returns index of the run which contains $ikey
+ */
+static inline int32_t rle16_find_run(const rle16_t *array, int32_t lenarray,
+ uint16_t ikey) {
+ int32_t low = 0;
+ int32_t high = lenarray - 1;
+ while (low <= high) {
+ int32_t middleIndex = (low + high) >> 1;
+ uint16_t min = array[middleIndex].value;
+ uint16_t max = array[middleIndex].value + array[middleIndex].length;
+ if (ikey > max) {
+ low = middleIndex + 1;
+ } else if (ikey < min) {
+ high = middleIndex - 1;
+ } else {
+ return middleIndex;
+ }
+ }
+ return -(low + 1);
+}
+
+
+/**
+ * Returns number of runs which can'be be merged with the key because they
+ * are less than the key.
+ * Note that [5,6,7,8] can be merged with the key 9 and won't be counted.
+ */
+static inline int32_t rle16_count_less(const rle16_t* array, int32_t lenarray,
+ uint16_t key) {
+ if (lenarray == 0) return 0;
+ int32_t low = 0;
+ int32_t high = lenarray - 1;
+ while (low <= high) {
+ int32_t middleIndex = (low + high) >> 1;
+ uint16_t min_value = array[middleIndex].value;
+ uint16_t max_value = array[middleIndex].value + array[middleIndex].length;
+ if (max_value + UINT32_C(1) < key) { // uint32 arithmetic
+ low = middleIndex + 1;
+ } else if (key < min_value) {
+ high = middleIndex - 1;
+ } else {
+ return middleIndex;
+ }
+ }
+ return low;
+}
+
+static inline int32_t rle16_count_greater(const rle16_t* array, int32_t lenarray,
+ uint16_t key) {
+ if (lenarray == 0) return 0;
+ int32_t low = 0;
+ int32_t high = lenarray - 1;
+ while (low <= high) {
+ int32_t middleIndex = (low + high) >> 1;
+ uint16_t min_value = array[middleIndex].value;
+ uint16_t max_value = array[middleIndex].value + array[middleIndex].length;
+ if (max_value < key) {
+ low = middleIndex + 1;
+ } else if (key + UINT32_C(1) < min_value) { // uint32 arithmetic
+ high = middleIndex - 1;
+ } else {
+ return lenarray - (middleIndex + 1);
+ }
+ }
+ return lenarray - low;
+}
+
+/**
+ * increase capacity to at least min. Whether the
+ * existing data needs to be copied over depends on copy. If "copy" is false,
+ * then the new content will be uninitialized, otherwise a copy is made.
+ */
+void run_container_grow(run_container_t *run, int32_t min, bool copy);
+
+/**
+ * Moves the data so that we can write data at index
+ */
+static inline void makeRoomAtIndex(run_container_t *run, uint16_t index) {
+ /* This function calls realloc + memmove sequentially to move by one index.
+ * Potentially copying twice the array.
+ */
+ if (run->n_runs + 1 > run->capacity)
+ run_container_grow(run, run->n_runs + 1, true);
+ memmove(run->runs + 1 + index, run->runs + index,
+ (run->n_runs - index) * sizeof(rle16_t));
+ run->n_runs++;
+}
+
+/* Add `pos' to `run'. Returns true if `pos' was not present. */
+bool run_container_add(run_container_t *run, uint16_t pos);
+
+/* Remove `pos' from `run'. Returns true if `pos' was present. */
+static inline bool run_container_remove(run_container_t *run, uint16_t pos) {
+ int32_t index = interleavedBinarySearch(run->runs, run->n_runs, pos);
+ if (index >= 0) {
+ int32_t le = run->runs[index].length;
+ if (le == 0) {
+ recoverRoomAtIndex(run, (uint16_t)index);
+ } else {
+ run->runs[index].value++;
+ run->runs[index].length--;
+ }
+ return true;
+ }
+ index = -index - 2; // points to preceding value, possibly -1
+ if (index >= 0) { // possible match
+ int32_t offset = pos - run->runs[index].value;
+ int32_t le = run->runs[index].length;
+ if (offset < le) {
+ // need to break in two
+ run->runs[index].length = (uint16_t)(offset - 1);
+ // need to insert
+ uint16_t newvalue = pos + 1;
+ int32_t newlength = le - offset - 1;
+ makeRoomAtIndex(run, (uint16_t)(index + 1));
+ run->runs[index + 1].value = newvalue;
+ run->runs[index + 1].length = (uint16_t)newlength;
+ return true;
+
+ } else if (offset == le) {
+ run->runs[index].length--;
+ return true;
+ }
+ }
+ // no match
+ return false;
+}
+
+/* Check whether `pos' is present in `run'. */
+static inline bool run_container_contains(const run_container_t *run, uint16_t pos) {
+ int32_t index = interleavedBinarySearch(run->runs, run->n_runs, pos);
+ if (index >= 0) return true;
+ index = -index - 2; // points to preceding value, possibly -1
+ if (index != -1) { // possible match
+ int32_t offset = pos - run->runs[index].value;
+ int32_t le = run->runs[index].length;
+ if (offset <= le) return true;
+ }
+ return false;
+}
+
+/*
+* Check whether all positions in a range of positions from pos_start (included)
+* to pos_end (excluded) is present in `run'.
+*/
+static inline bool run_container_contains_range(const run_container_t *run,
+ uint32_t pos_start, uint32_t pos_end) {
+ uint32_t count = 0;
+ int32_t index = interleavedBinarySearch(run->runs, run->n_runs, pos_start);
+ if (index < 0) {
+ index = -index - 2;
+ if ((index == -1) || ((pos_start - run->runs[index].value) > run->runs[index].length)){
+ return false;
+ }
+ }
+ for (int32_t i = index; i < run->n_runs; ++i) {
+ const uint32_t stop = run->runs[i].value + run->runs[i].length;
+ if (run->runs[i].value >= pos_end) break;
+ if (stop >= pos_end) {
+ count += (((pos_end - run->runs[i].value) > 0) ? (pos_end - run->runs[i].value) : 0);
+ break;
+ }
+ const uint32_t min = (stop - pos_start) > 0 ? (stop - pos_start) : 0;
+ count += (min < run->runs[i].length) ? min : run->runs[i].length;
+ }
+ return count >= (pos_end - pos_start - 1);
+}
+
+#ifdef USEAVX
+
+/* Get the cardinality of `run'. Requires an actual computation. */
+static inline int run_container_cardinality(const run_container_t *run) {
+ const int32_t n_runs = run->n_runs;
+ const rle16_t *runs = run->runs;
+
+ /* by initializing with n_runs, we omit counting the +1 for each pair. */
+ int sum = n_runs;
+ int32_t k = 0;
+ const int32_t step = sizeof(__m256i) / sizeof(rle16_t);
+ if (n_runs > step) {
+ __m256i total = _mm256_setzero_si256();
+ for (; k + step <= n_runs; k += step) {
+ __m256i ymm1 = _mm256_lddqu_si256((const __m256i *)(runs + k));
+ __m256i justlengths = _mm256_srli_epi32(ymm1, 16);
+ total = _mm256_add_epi32(total, justlengths);
+ }
+ // a store might be faster than extract?
+ uint32_t buffer[sizeof(__m256i) / sizeof(rle16_t)];
+ _mm256_storeu_si256((__m256i *)buffer, total);
+ sum += (buffer[0] + buffer[1]) + (buffer[2] + buffer[3]) +
+ (buffer[4] + buffer[5]) + (buffer[6] + buffer[7]);
+ }
+ for (; k < n_runs; ++k) {
+ sum += runs[k].length;
+ }
+
+ return sum;
+}
+
+#else
+
+/* Get the cardinality of `run'. Requires an actual computation. */
+static inline int run_container_cardinality(const run_container_t *run) {
+ const int32_t n_runs = run->n_runs;
+ const rle16_t *runs = run->runs;
+
+ /* by initializing with n_runs, we omit counting the +1 for each pair. */
+ int sum = n_runs;
+ for (int k = 0; k < n_runs; ++k) {
+ sum += runs[k].length;
+ }
+
+ return sum;
+}
+#endif
+
+/* Card > 0?, see run_container_empty for the reverse */
+static inline bool run_container_nonzero_cardinality(
+ const run_container_t *run) {
+ return run->n_runs > 0; // runs never empty
+}
+
+/* Card == 0?, see run_container_nonzero_cardinality for the reverse */
+static inline bool run_container_empty(
+ const run_container_t *run) {
+ return run->n_runs == 0; // runs never empty
+}
+
+
+
+/* Copy one container into another. We assume that they are distinct. */
+void run_container_copy(const run_container_t *src, run_container_t *dst);
+
+/* Set the cardinality to zero (does not release memory). */
+static inline void run_container_clear(run_container_t *run) {
+ run->n_runs = 0;
+}
+
+/**
+ * Append run described by vl to the run container, possibly merging.
+ * It is assumed that the run would be inserted at the end of the container, no
+ * check is made.
+ * It is assumed that the run container has the necessary capacity: caller is
+ * responsible for checking memory capacity.
+ *
+ *
+ * This is not a safe function, it is meant for performance: use with care.
+ */
+static inline void run_container_append(run_container_t *run, rle16_t vl,
+ rle16_t *previousrl) {
+ const uint32_t previousend = previousrl->value + previousrl->length;
+ if (vl.value > previousend + 1) { // we add a new one
+ run->runs[run->n_runs] = vl;
+ run->n_runs++;
+ *previousrl = vl;
+ } else {
+ uint32_t newend = vl.value + vl.length + UINT32_C(1);
+ if (newend > previousend) { // we merge
+ previousrl->length = (uint16_t)(newend - 1 - previousrl->value);
+ run->runs[run->n_runs - 1] = *previousrl;
+ }
+ }
+}
+
+/**
+ * Like run_container_append but it is assumed that the content of run is empty.
+ */
+static inline rle16_t run_container_append_first(run_container_t *run,
+ rle16_t vl) {
+ run->runs[run->n_runs] = vl;
+ run->n_runs++;
+ return vl;
+}
+
+/**
+ * append a single value given by val to the run container, possibly merging.
+ * It is assumed that the value would be inserted at the end of the container,
+ * no check is made.
+ * It is assumed that the run container has the necessary capacity: caller is
+ * responsible for checking memory capacity.
+ *
+ * This is not a safe function, it is meant for performance: use with care.
+ */
+static inline void run_container_append_value(run_container_t *run,
+ uint16_t val,
+ rle16_t *previousrl) {
+ const uint32_t previousend = previousrl->value + previousrl->length;
+ if (val > previousend + 1) { // we add a new one
+ //*previousrl = (rle16_t){.value = val, .length = 0};// requires C99
+ previousrl->value = val;
+ previousrl->length = 0;
+
+ run->runs[run->n_runs] = *previousrl;
+ run->n_runs++;
+ } else if (val == previousend + 1) { // we merge
+ previousrl->length++;
+ run->runs[run->n_runs - 1] = *previousrl;
+ }
+}
+
+/**
+ * Like run_container_append_value but it is assumed that the content of run is
+ * empty.
+ */
+static inline rle16_t run_container_append_value_first(run_container_t *run,
+ uint16_t val) {
+ // rle16_t newrle = (rle16_t){.value = val, .length = 0};// requires C99
+ rle16_t newrle;
+ newrle.value = val;
+ newrle.length = 0;
+
+ run->runs[run->n_runs] = newrle;
+ run->n_runs++;
+ return newrle;
+}
+
+/* Check whether the container spans the whole chunk (cardinality = 1<<16).
+ * This check can be done in constant time (inexpensive). */
+static inline bool run_container_is_full(const run_container_t *run) {
+ rle16_t vl = run->runs[0];
+ return (run->n_runs == 1) && (vl.value == 0) && (vl.length == 0xFFFF);
+}
+
+/* Compute the union of `src_1' and `src_2' and write the result to `dst'
+ * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
+void run_container_union(const run_container_t *src_1,
+ const run_container_t *src_2, run_container_t *dst);
+
+/* Compute the union of `src_1' and `src_2' and write the result to `src_1' */
+void run_container_union_inplace(run_container_t *src_1,
+ const run_container_t *src_2);
+
+/* Compute the intersection of src_1 and src_2 and write the result to
+ * dst. It is assumed that dst is distinct from both src_1 and src_2. */
+void run_container_intersection(const run_container_t *src_1,
+ const run_container_t *src_2,
+ run_container_t *dst);
+
+/* Compute the size of the intersection of src_1 and src_2 . */
+int run_container_intersection_cardinality(const run_container_t *src_1,
+ const run_container_t *src_2);
+
+/* Check whether src_1 and src_2 intersect. */
+bool run_container_intersect(const run_container_t *src_1,
+ const run_container_t *src_2);
+
+/* Compute the symmetric difference of `src_1' and `src_2' and write the result
+ * to `dst'
+ * It is assumed that `dst' is distinct from both `src_1' and `src_2'. */
+void run_container_xor(const run_container_t *src_1,
+ const run_container_t *src_2, run_container_t *dst);
+
+/*
+ * Write out the 16-bit integers contained in this container as a list of 32-bit
+ * integers using base
+ * as the starting value (it might be expected that base has zeros in its 16
+ * least significant bits).
+ * The function returns the number of values written.
+ * The caller is responsible for allocating enough memory in out.
+ */
+int run_container_to_uint32_array(void *vout, const run_container_t *cont,
+ uint32_t base);
+
+/*
+ * Print this container using printf (useful for debugging).
+ */
+void run_container_printf(const run_container_t *v);
+
+/*
+ * Print this container using printf as a comma-separated list of 32-bit
+ * integers starting at base.
+ */
+void run_container_printf_as_uint32_array(const run_container_t *v,
+ uint32_t base);
+
+/**
+ * Return the serialized size in bytes of a container having "num_runs" runs.
+ */
+static inline int32_t run_container_serialized_size_in_bytes(int32_t num_runs) {
+ return sizeof(uint16_t) +
+ sizeof(rle16_t) * num_runs; // each run requires 2 2-byte entries.
+}
+
+bool run_container_iterate(const run_container_t *cont, uint32_t base,
+ roaring_iterator iterator, void *ptr);
+bool run_container_iterate64(const run_container_t *cont, uint32_t base,
+ roaring_iterator64 iterator, uint64_t high_bits,
+ void *ptr);
+
+/**
+ * Writes the underlying array to buf, outputs how many bytes were written.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes written should be run_container_size_in_bytes(container).
+ */
+int32_t run_container_write(const run_container_t *container, char *buf);
+
+/**
+ * Reads the instance from buf, outputs how many bytes were read.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes read should be bitset_container_size_in_bytes(container).
+ * The cardinality parameter is provided for consistency with other containers,
+ * but
+ * it might be effectively ignored..
+ */
+int32_t run_container_read(int32_t cardinality, run_container_t *container,
+ const char *buf);
+
+/**
+ * Return the serialized size in bytes of a container (see run_container_write).
+ * This is meant to be compatible with the Java and Go versions of Roaring.
+ */
+static inline int32_t run_container_size_in_bytes(
+ const run_container_t *container) {
+ return run_container_serialized_size_in_bytes(container->n_runs);
+}
+
+/**
+ * Return true if the two containers have the same content.
+ */
+static inline bool run_container_equals(const run_container_t *container1,
+ const run_container_t *container2) {
+ if (container1->n_runs != container2->n_runs) {
+ return false;
+ }
+ return memequals(container1->runs, container2->runs,
+ container1->n_runs * sizeof(rle16_t));
+}
+
+/**
+* Return true if container1 is a subset of container2.
+*/
+bool run_container_is_subset(const run_container_t *container1,
+ const run_container_t *container2);
+
+/**
+ * Used in a start-finish scan that appends segments, for XOR and NOT
+ */
+
+void run_container_smart_append_exclusive(run_container_t *src,
+ const uint16_t start,
+ const uint16_t length);
+
+/**
+* The new container consists of a single run [start,stop).
+* It is required that stop>start, the caller is responsibility for this check.
+* It is required that stop <= (1<<16), the caller is responsibility for this check.
+* The cardinality of the created container is stop - start.
+* Returns NULL on failure
+*/
+static inline run_container_t *run_container_create_range(uint32_t start,
+ uint32_t stop) {
+ run_container_t *rc = run_container_create_given_capacity(1);
+ if (rc) {
+ rle16_t r;
+ r.value = (uint16_t)start;
+ r.length = (uint16_t)(stop - start - 1);
+ run_container_append_first(rc, r);
+ }
+ return rc;
+}
+
+/**
+ * If the element of given rank is in this container, supposing that the first
+ * element has rank start_rank, then the function returns true and sets element
+ * accordingly.
+ * Otherwise, it returns false and update start_rank.
+ */
+bool run_container_select(const run_container_t *container,
+ uint32_t *start_rank, uint32_t rank,
+ uint32_t *element);
+
+/* Compute the difference of src_1 and src_2 and write the result to
+ * dst. It is assumed that dst is distinct from both src_1 and src_2. */
+
+void run_container_andnot(const run_container_t *src_1,
+ const run_container_t *src_2, run_container_t *dst);
+
+/* Returns the smallest value (assumes not empty) */
+static inline uint16_t run_container_minimum(const run_container_t *run) {
+ if (run->n_runs == 0) return 0;
+ return run->runs[0].value;
+}
+
+/* Returns the largest value (assumes not empty) */
+static inline uint16_t run_container_maximum(const run_container_t *run) {
+ if (run->n_runs == 0) return 0;
+ return run->runs[run->n_runs - 1].value + run->runs[run->n_runs - 1].length;
+}
+
+/* Returns the number of values equal or smaller than x */
+int run_container_rank(const run_container_t *arr, uint16_t x);
+
+/* Returns the index of the first run containing a value at least as large as x, or -1 */
+static inline int run_container_index_equalorlarger(const run_container_t *arr, uint16_t x) {
+ int32_t index = interleavedBinarySearch(arr->runs, arr->n_runs, x);
+ if (index >= 0) return index;
+ index = -index - 2; // points to preceding run, possibly -1
+ if (index != -1) { // possible match
+ int32_t offset = x - arr->runs[index].value;
+ int32_t le = arr->runs[index].length;
+ if (offset <= le) return index;
+ }
+ index += 1;
+ if(index < arr->n_runs) {
+ return index;
+ }
+ return -1;
+}
+
+/*
+ * Add all values in range [min, max] using hint.
+ */
+static inline void run_container_add_range_nruns(run_container_t* run,
+ uint32_t min, uint32_t max,
+ int32_t nruns_less,
+ int32_t nruns_greater) {
+ int32_t nruns_common = run->n_runs - nruns_less - nruns_greater;
+ if (nruns_common == 0) {
+ makeRoomAtIndex(run, nruns_less);
+ run->runs[nruns_less].value = min;
+ run->runs[nruns_less].length = max - min;
+ } else {
+ uint32_t common_min = run->runs[nruns_less].value;
+ uint32_t common_max = run->runs[nruns_less + nruns_common - 1].value +
+ run->runs[nruns_less + nruns_common - 1].length;
+ uint32_t result_min = (common_min < min) ? common_min : min;
+ uint32_t result_max = (common_max > max) ? common_max : max;
+
+ run->runs[nruns_less].value = result_min;
+ run->runs[nruns_less].length = result_max - result_min;
+
+ memmove(&(run->runs[nruns_less + 1]),
+ &(run->runs[run->n_runs - nruns_greater]),
+ nruns_greater*sizeof(rle16_t));
+ run->n_runs = nruns_less + 1 + nruns_greater;
+ }
+}
+
+/**
+ * Add all values in range [min, max]
+ */
+static inline void run_container_add_range(run_container_t* run,
+ uint32_t min, uint32_t max) {
+ int32_t nruns_greater = rle16_count_greater(run->runs, run->n_runs, max);
+ int32_t nruns_less = rle16_count_less(run->runs, run->n_runs - nruns_greater, min);
+ run_container_add_range_nruns(run, min, max, nruns_less, nruns_greater);
+}
+
+/**
+ * Shifts last $count elements either left (distance < 0) or right (distance > 0)
+ */
+static inline void run_container_shift_tail(run_container_t* run,
+ int32_t count, int32_t distance) {
+ if (distance > 0) {
+ if (run->capacity < count+distance) {
+ run_container_grow(run, count+distance, true);
+ }
+ }
+ int32_t srcpos = run->n_runs - count;
+ int32_t dstpos = srcpos + distance;
+ memmove(&(run->runs[dstpos]), &(run->runs[srcpos]), sizeof(rle16_t) * count);
+ run->n_runs += distance;
+}
+
+/**
+ * Remove all elements in range [min, max]
+ */
+static inline void run_container_remove_range(run_container_t *run, uint32_t min, uint32_t max) {
+ int32_t first = rle16_find_run(run->runs, run->n_runs, min);
+ int32_t last = rle16_find_run(run->runs, run->n_runs, max);
+
+ if (first >= 0 && min > run->runs[first].value &&
+ max < ((uint32_t)run->runs[first].value + (uint32_t)run->runs[first].length)) {
+ // split this run into two adjacent runs
+
+ // right subinterval
+ makeRoomAtIndex(run, first+1);
+ run->runs[first+1].value = max + 1;
+ run->runs[first+1].length = (run->runs[first].value + run->runs[first].length) - (max + 1);
+
+ // left subinterval
+ run->runs[first].length = (min - 1) - run->runs[first].value;
+
+ return;
+ }
+
+ // update left-most partial run
+ if (first >= 0) {
+ if (min > run->runs[first].value) {
+ run->runs[first].length = (min - 1) - run->runs[first].value;
+ first++;
+ }
+ } else {
+ first = -first-1;
+ }
+
+ // update right-most run
+ if (last >= 0) {
+ uint16_t run_max = run->runs[last].value + run->runs[last].length;
+ if (run_max > max) {
+ run->runs[last].value = max + 1;
+ run->runs[last].length = run_max - (max + 1);
+ last--;
+ }
+ } else {
+ last = (-last-1) - 1;
+ }
+
+ // remove intermediate runs
+ if (first <= last) {
+ run_container_shift_tail(run, run->n_runs - (last+1), -(last-first+1));
+ }
+}
+
+
+#endif /* INCLUDE_CONTAINERS_RUN_H_ */
+/* end file include/roaring/containers/run.h */
+/* begin file include/roaring/containers/convert.h */
+/*
+ * convert.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_CONVERT_H_
+#define INCLUDE_CONTAINERS_CONVERT_H_
+
+
+/* Convert an array into a bitset. The input container is not freed or modified.
+ */
+bitset_container_t *bitset_container_from_array(const array_container_t *arr);
+
+/* Convert a run into a bitset. The input container is not freed or modified. */
+bitset_container_t *bitset_container_from_run(const run_container_t *arr);
+
+/* Convert a run into an array. The input container is not freed or modified. */
+array_container_t *array_container_from_run(const run_container_t *arr);
+
+/* Convert a bitset into an array. The input container is not freed or modified.
+ */
+array_container_t *array_container_from_bitset(const bitset_container_t *bits);
+
+/* Convert an array into a run. The input container is not freed or modified.
+ */
+run_container_t *run_container_from_array(const array_container_t *c);
+
+/* convert a run into either an array or a bitset
+ * might free the container. This does not free the input run container. */
+void *convert_to_bitset_or_array_container(run_container_t *r, int32_t card,
+ uint8_t *resulttype);
+
+/* convert containers to and from runcontainers, as is most space efficient.
+ * The container might be freed. */
+void *convert_run_optimize(void *c, uint8_t typecode_original,
+ uint8_t *typecode_after);
+
+/* converts a run container to either an array or a bitset, IF it saves space.
+ */
+/* If a conversion occurs, the caller is responsible to free the original
+ * container and
+ * he becomes responsible to free the new one. */
+void *convert_run_to_efficient_container(run_container_t *c,
+ uint8_t *typecode_after);
+// like convert_run_to_efficient_container but frees the old result if needed
+void *convert_run_to_efficient_container_and_free(run_container_t *c,
+ uint8_t *typecode_after);
+
+/**
+ * Create new bitset container which is a union of run container and
+ * range [min, max]. Caller is responsible for freeing run container.
+ */
+bitset_container_t *bitset_container_from_run_range(const run_container_t *run,
+ uint32_t min, uint32_t max);
+
+#endif /* INCLUDE_CONTAINERS_CONVERT_H_ */
+/* end file include/roaring/containers/convert.h */
+/* begin file include/roaring/containers/mixed_equal.h */
+/*
+ * mixed_equal.h
+ *
+ */
+
+#ifndef CONTAINERS_MIXED_EQUAL_H_
+#define CONTAINERS_MIXED_EQUAL_H_
+
+
+/**
+ * Return true if the two containers have the same content.
+ */
+bool array_container_equal_bitset(const array_container_t* container1,
+ const bitset_container_t* container2);
+
+/**
+ * Return true if the two containers have the same content.
+ */
+bool run_container_equals_array(const run_container_t* container1,
+ const array_container_t* container2);
+/**
+ * Return true if the two containers have the same content.
+ */
+bool run_container_equals_bitset(const run_container_t* container1,
+ const bitset_container_t* container2);
+
+#endif /* CONTAINERS_MIXED_EQUAL_H_ */
+/* end file include/roaring/containers/mixed_equal.h */
+/* begin file include/roaring/containers/mixed_subset.h */
+/*
+ * mixed_subset.h
+ *
+ */
+
+#ifndef CONTAINERS_MIXED_SUBSET_H_
+#define CONTAINERS_MIXED_SUBSET_H_
+
+
+/**
+ * Return true if container1 is a subset of container2.
+ */
+bool array_container_is_subset_bitset(const array_container_t* container1,
+ const bitset_container_t* container2);
+
+/**
+* Return true if container1 is a subset of container2.
+ */
+bool run_container_is_subset_array(const run_container_t* container1,
+ const array_container_t* container2);
+
+/**
+* Return true if container1 is a subset of container2.
+ */
+bool array_container_is_subset_run(const array_container_t* container1,
+ const run_container_t* container2);
+
+/**
+* Return true if container1 is a subset of container2.
+ */
+bool run_container_is_subset_bitset(const run_container_t* container1,
+ const bitset_container_t* container2);
+
+/**
+* Return true if container1 is a subset of container2.
+*/
+bool bitset_container_is_subset_run(const bitset_container_t* container1,
+ const run_container_t* container2);
+
+#endif /* CONTAINERS_MIXED_SUBSET_H_ */
+/* end file include/roaring/containers/mixed_subset.h */
+/* begin file include/roaring/containers/mixed_andnot.h */
+/*
+ * mixed_andnot.h
+ */
+#ifndef INCLUDE_CONTAINERS_MIXED_ANDNOT_H_
+#define INCLUDE_CONTAINERS_MIXED_ANDNOT_H_
+
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst, a valid array container that could be the same as dst.*/
+void array_bitset_container_andnot(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ array_container_t *dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * src_1 */
+
+void array_bitset_container_iandnot(array_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst, which does not initially have a valid container.
+ * Return true for a bitset result; false for array
+ */
+
+bool bitset_array_container_andnot(const bitset_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_array_container_iandnot(bitset_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_andnot(const run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_iandnot(run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool bitset_run_container_andnot(const bitset_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_run_container_iandnot(bitset_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any type of container.
+ */
+
+int run_array_container_andnot(const run_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+int run_array_container_iandnot(run_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/* dst must be a valid array container, allowed to be src_1 */
+
+void array_run_container_andnot(const array_container_t *src_1,
+ const run_container_t *src_2,
+ array_container_t *dst);
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+void array_run_container_iandnot(array_container_t *src_1,
+ const run_container_t *src_2);
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int run_run_container_andnot(const run_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+int run_run_container_iandnot(run_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/*
+ * dst is a valid array container and may be the same as src_1
+ */
+
+void array_array_container_andnot(const array_container_t *src_1,
+ const array_container_t *src_2,
+ array_container_t *dst);
+
+/* inplace array-array andnot will always be able to reuse the space of
+ * src_1 */
+void array_array_container_iandnot(array_container_t *src_1,
+ const array_container_t *src_2);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). Return value is
+ * "dst is a bitset"
+ */
+
+bool bitset_bitset_container_andnot(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst);
+
+/* Compute the andnot of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_bitset_container_iandnot(bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst);
+#endif
+/* end file include/roaring/containers/mixed_andnot.h */
+/* begin file include/roaring/containers/mixed_intersection.h */
+/*
+ * mixed_intersection.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_MIXED_INTERSECTION_H_
+#define INCLUDE_CONTAINERS_MIXED_INTERSECTION_H_
+
+/* These functions appear to exclude cases where the
+ * inputs have the same type and the output is guaranteed
+ * to have the same type as the inputs. Eg, array intersection
+ */
+
+
+/* Compute the intersection of src_1 and src_2 and write the result to
+ * dst. It is allowed for dst to be equal to src_1. We assume that dst is a
+ * valid container. */
+void array_bitset_container_intersection(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ array_container_t *dst);
+
+/* Compute the size of the intersection of src_1 and src_2. */
+int array_bitset_container_intersection_cardinality(
+ const array_container_t *src_1, const bitset_container_t *src_2);
+
+
+
+/* Checking whether src_1 and src_2 intersect. */
+bool array_bitset_container_intersect(const array_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/*
+ * Compute the intersection between src_1 and src_2 and write the result
+ * to *dst. If the return function is true, the result is a bitset_container_t
+ * otherwise is a array_container_t. We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+bool bitset_bitset_container_intersection(const bitset_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst);
+
+/* Compute the intersection between src_1 and src_2 and write the result to
+ * dst. It is allowed for dst to be equal to src_1. We assume that dst is a
+ * valid container. */
+void array_run_container_intersection(const array_container_t *src_1,
+ const run_container_t *src_2,
+ array_container_t *dst);
+
+/* Compute the intersection between src_1 and src_2 and write the result to
+ * *dst. If the result is true then the result is a bitset_container_t
+ * otherwise is a array_container_t.
+ * If *dst == src_2, then an in-place intersection is attempted
+ **/
+bool run_bitset_container_intersection(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ void **dst);
+
+/* Compute the size of the intersection between src_1 and src_2 . */
+int array_run_container_intersection_cardinality(const array_container_t *src_1,
+ const run_container_t *src_2);
+
+/* Compute the size of the intersection between src_1 and src_2
+ **/
+int run_bitset_container_intersection_cardinality(const run_container_t *src_1,
+ const bitset_container_t *src_2);
+
+
+/* Check that src_1 and src_2 intersect. */
+bool array_run_container_intersect(const array_container_t *src_1,
+ const run_container_t *src_2);
+
+/* Check that src_1 and src_2 intersect.
+ **/
+bool run_bitset_container_intersect(const run_container_t *src_1,
+ const bitset_container_t *src_2);
+
+/*
+ * Same as bitset_bitset_container_intersection except that if the output is to
+ * be a
+ * bitset_container_t, then src_1 is modified and no allocation is made.
+ * If the output is to be an array_container_t, then caller is responsible
+ * to free the container.
+ * In all cases, the result is in *dst.
+ */
+bool bitset_bitset_container_intersection_inplace(
+ bitset_container_t *src_1, const bitset_container_t *src_2, void **dst);
+
+#endif /* INCLUDE_CONTAINERS_MIXED_INTERSECTION_H_ */
+/* end file include/roaring/containers/mixed_intersection.h */
+/* begin file include/roaring/containers/mixed_negation.h */
+/*
+ * mixed_negation.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_MIXED_NEGATION_H_
+#define INCLUDE_CONTAINERS_MIXED_NEGATION_H_
+
+
+/* Negation across the entire range of the container.
+ * Compute the negation of src and write the result
+ * to *dst. The complement of a
+ * sufficiently sparse set will always be dense and a hence a bitmap
+ * We assume that dst is pre-allocated and a valid bitset container
+ * There can be no in-place version.
+ */
+void array_container_negation(const array_container_t *src,
+ bitset_container_t *dst);
+
+/* Negation across the entire range of the container
+ * Compute the negation of src and write the result
+ * to *dst. A true return value indicates a bitset result,
+ * otherwise the result is an array container.
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+bool bitset_container_negation(const bitset_container_t *src, void **dst);
+
+/* inplace version */
+/*
+ * Same as bitset_container_negation except that if the output is to
+ * be a
+ * bitset_container_t, then src is modified and no allocation is made.
+ * If the output is to be an array_container_t, then caller is responsible
+ * to free the container.
+ * In all cases, the result is in *dst.
+ */
+bool bitset_container_negation_inplace(bitset_container_t *src, void **dst);
+
+/* Negation across the entire range of container
+ * Compute the negation of src and write the result
+ * to *dst.
+ * Return values are the *_TYPECODES as defined * in containers.h
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+int run_container_negation(const run_container_t *src, void **dst);
+
+/*
+ * Same as run_container_negation except that if the output is to
+ * be a
+ * run_container_t, and has the capacity to hold the result,
+ * then src is modified and no allocation is made.
+ * In all cases, the result is in *dst.
+ */
+int run_container_negation_inplace(run_container_t *src, void **dst);
+
+/* Negation across a range of the container.
+ * Compute the negation of src and write the result
+ * to *dst. Returns true if the result is a bitset container
+ * and false for an array container. *dst is not preallocated.
+ */
+bool array_container_negation_range(const array_container_t *src,
+ const int range_start, const int range_end,
+ void **dst);
+
+/* Even when the result would fit, it is unclear how to make an
+ * inplace version without inefficient copying. Thus this routine
+ * may be a wrapper for the non-in-place version
+ */
+bool array_container_negation_range_inplace(array_container_t *src,
+ const int range_start,
+ const int range_end, void **dst);
+
+/* Negation across a range of the container
+ * Compute the negation of src and write the result
+ * to *dst. A true return value indicates a bitset result,
+ * otherwise the result is an array container.
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+bool bitset_container_negation_range(const bitset_container_t *src,
+ const int range_start, const int range_end,
+ void **dst);
+
+/* inplace version */
+/*
+ * Same as bitset_container_negation except that if the output is to
+ * be a
+ * bitset_container_t, then src is modified and no allocation is made.
+ * If the output is to be an array_container_t, then caller is responsible
+ * to free the container.
+ * In all cases, the result is in *dst.
+ */
+bool bitset_container_negation_range_inplace(bitset_container_t *src,
+ const int range_start,
+ const int range_end, void **dst);
+
+/* Negation across a range of container
+ * Compute the negation of src and write the result
+ * to *dst. Return values are the *_TYPECODES as defined * in containers.h
+ * We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+int run_container_negation_range(const run_container_t *src,
+ const int range_start, const int range_end,
+ void **dst);
+
+/*
+ * Same as run_container_negation except that if the output is to
+ * be a
+ * run_container_t, and has the capacity to hold the result,
+ * then src is modified and no allocation is made.
+ * In all cases, the result is in *dst.
+ */
+int run_container_negation_range_inplace(run_container_t *src,
+ const int range_start,
+ const int range_end, void **dst);
+
+#endif /* INCLUDE_CONTAINERS_MIXED_NEGATION_H_ */
+/* end file include/roaring/containers/mixed_negation.h */
+/* begin file include/roaring/containers/mixed_union.h */
+/*
+ * mixed_intersection.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_MIXED_UNION_H_
+#define INCLUDE_CONTAINERS_MIXED_UNION_H_
+
+/* These functions appear to exclude cases where the
+ * inputs have the same type and the output is guaranteed
+ * to have the same type as the inputs. Eg, bitset unions
+ */
+
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. It is allowed for src_2 to be dst. */
+void array_bitset_container_union(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. It is allowed for src_2 to be dst. This version does not
+ * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY). */
+void array_bitset_container_lazy_union(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/*
+ * Compute the union between src_1 and src_2 and write the result
+ * to *dst. If the return function is true, the result is a bitset_container_t
+ * otherwise is a array_container_t. We assume that dst is not pre-allocated. In
+ * case of failure, *dst will be NULL.
+ */
+bool array_array_container_union(const array_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/*
+ * Compute the union between src_1 and src_2 and write the result
+ * to *dst if it cannot be written to src_1. If the return function is true,
+ * the result is a bitset_container_t
+ * otherwise is a array_container_t. When the result is an array_container_t, it
+ * it either written to src_1 (if *dst is null) or to *dst.
+ * If the result is a bitset_container_t and *dst is null, then there was a failure.
+ */
+bool array_array_container_inplace_union(array_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/*
+ * Same as array_array_container_union except that it will more eagerly produce
+ * a bitset.
+ */
+bool array_array_container_lazy_union(const array_container_t *src_1,
+ const array_container_t *src_2,
+ void **dst);
+
+/*
+ * Same as array_array_container_inplace_union except that it will more eagerly produce
+ * a bitset.
+ */
+bool array_array_container_lazy_inplace_union(array_container_t *src_1,
+ const array_container_t *src_2,
+ void **dst);
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. We assume that dst is a
+ * valid container. The result might need to be further converted to array or
+ * bitset container,
+ * the caller is responsible for the eventual conversion. */
+void array_run_container_union(const array_container_t *src_1,
+ const run_container_t *src_2,
+ run_container_t *dst);
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * src2. The result might need to be further converted to array or
+ * bitset container,
+ * the caller is responsible for the eventual conversion. */
+void array_run_container_inplace_union(const array_container_t *src_1,
+ run_container_t *src_2);
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. It is allowed for dst to be src_2.
+ * If run_container_is_full(src_1) is true, you must not be calling this
+ *function.
+ **/
+void run_bitset_container_union(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* Compute the union of src_1 and src_2 and write the result to
+ * dst. It is allowed for dst to be src_2. This version does not
+ * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY).
+ * If run_container_is_full(src_1) is true, you must not be calling this
+ * function.
+ * */
+void run_bitset_container_lazy_union(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+#endif /* INCLUDE_CONTAINERS_MIXED_UNION_H_ */
+/* end file include/roaring/containers/mixed_union.h */
+/* begin file include/roaring/containers/mixed_xor.h */
+/*
+ * mixed_xor.h
+ *
+ */
+
+#ifndef INCLUDE_CONTAINERS_MIXED_XOR_H_
+#define INCLUDE_CONTAINERS_MIXED_XOR_H_
+
+/* These functions appear to exclude cases where the
+ * inputs have the same type and the output is guaranteed
+ * to have the same type as the inputs. Eg, bitset unions
+ */
+
+/*
+ * Java implementation (as of May 2016) for array_run, run_run
+ * and bitset_run don't do anything different for inplace.
+ * (They are not truly in place.)
+ */
+
+
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst (which has no container initially).
+ * Result is true iff dst is a bitset */
+bool array_bitset_container_xor(const array_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst. It is allowed for src_2 to be dst. This version does not
+ * update the cardinality of dst (it is set to BITSET_UNKNOWN_CARDINALITY).
+ */
+
+void array_bitset_container_lazy_xor(const array_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst (which has no container initially). Return value is
+ * "dst is a bitset"
+ */
+
+bool bitset_bitset_container_xor(const bitset_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_xor(const run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+/* lazy xor. Dst is initialized and may be equal to src_2.
+ * Result is left as a bitset container, even if actual
+ * cardinality would dictate an array container.
+ */
+
+void run_bitset_container_lazy_xor(const run_container_t *src_1,
+ const bitset_container_t *src_2,
+ bitset_container_t *dst);
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int array_run_container_xor(const array_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/* dst does not initially have a valid container. Creates either
+ * an array or a bitset container, indicated by return code
+ */
+
+bool array_array_container_xor(const array_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/* dst does not initially have a valid container. Creates either
+ * an array or a bitset container, indicated by return code.
+ * A bitset container will not have a valid cardinality and the
+ * container type might not be correct for the actual cardinality
+ */
+
+bool array_array_container_lazy_xor(const array_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+/* Dst is a valid run container. (Can it be src_2? Let's say not.)
+ * Leaves result as run container, even if other options are
+ * smaller.
+ */
+
+void array_run_container_lazy_xor(const array_container_t *src_1,
+ const run_container_t *src_2,
+ run_container_t *dst);
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int run_run_container_xor(const run_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/* INPLACE versions (initial implementation may not exploit all inplace
+ * opportunities (if any...)
+ */
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst (which has no container initially). It will modify src_1
+ * to be dst if the result is a bitset. Otherwise, it will
+ * free src_1 and dst will be a new array container. In both
+ * cases, the caller is responsible for deallocating dst.
+ * Returns true iff dst is a bitset */
+
+bool bitset_array_container_ixor(bitset_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+bool bitset_bitset_container_ixor(bitset_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+bool array_bitset_container_ixor(array_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+/* Compute the xor of src_1 and src_2 and write the result to
+ * dst. Result may be either a bitset or an array container
+ * (returns "result is bitset"). dst does not initially have
+ * any container, but becomes either a bitset container (return
+ * result true) or an array container.
+ */
+
+bool run_bitset_container_ixor(run_container_t *src_1,
+ const bitset_container_t *src_2, void **dst);
+
+bool bitset_run_container_ixor(bitset_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+/* dst does not indicate a valid container initially. Eventually it
+ * can become any kind of container.
+ */
+
+int array_run_container_ixor(array_container_t *src_1,
+ const run_container_t *src_2, void **dst);
+
+int run_array_container_ixor(run_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+bool array_array_container_ixor(array_container_t *src_1,
+ const array_container_t *src_2, void **dst);
+
+int run_run_container_ixor(run_container_t *src_1, const run_container_t *src_2,
+ void **dst);
+#endif
+/* end file include/roaring/containers/mixed_xor.h */
+/* begin file include/roaring/containers/containers.h */
+#ifndef CONTAINERS_CONTAINERS_H
+#define CONTAINERS_CONTAINERS_H
+
+#include
+#include
+#include
+
+
+// would enum be possible or better?
+
+/**
+ * The switch case statements follow
+ * BITSET_CONTAINER_TYPE_CODE -- ARRAY_CONTAINER_TYPE_CODE --
+ * RUN_CONTAINER_TYPE_CODE
+ * so it makes more sense to number them 1, 2, 3 (in the vague hope that the
+ * compiler might exploit this ordering).
+ */
+
+#define BITSET_CONTAINER_TYPE_CODE 1
+#define ARRAY_CONTAINER_TYPE_CODE 2
+#define RUN_CONTAINER_TYPE_CODE 3
+#define SHARED_CONTAINER_TYPE_CODE 4
+
+// macro for pairing container type codes
+#define CONTAINER_PAIR(c1, c2) (4 * (c1) + (c2))
+
+/**
+ * A shared container is a wrapper around a container
+ * with reference counting.
+ */
+
+struct shared_container_s {
+ void *container;
+ uint8_t typecode;
+ uint32_t counter; // to be managed atomically
+};
+
+typedef struct shared_container_s shared_container_t;
+
+/*
+ * With copy_on_write = true
+ * Create a new shared container if the typecode is not SHARED_CONTAINER_TYPE,
+ * otherwise, increase the count
+ * If copy_on_write = false, then clone.
+ * Return NULL in case of failure.
+ **/
+void *get_copy_of_container(void *container, uint8_t *typecode,
+ bool copy_on_write);
+
+/* Frees a shared container (actually decrement its counter and only frees when
+ * the counter falls to zero). */
+void shared_container_free(shared_container_t *container);
+
+/* extract a copy from the shared container, freeing the shared container if
+there is just one instance left,
+clone instances when the counter is higher than one
+*/
+void *shared_container_extract_copy(shared_container_t *container,
+ uint8_t *typecode);
+
+/* access to container underneath */
+static inline const void *container_unwrap_shared(
+ const void *candidate_shared_container, uint8_t *type) {
+ if (*type == SHARED_CONTAINER_TYPE_CODE) {
+ *type =
+ ((const shared_container_t *)candidate_shared_container)->typecode;
+ assert(*type != SHARED_CONTAINER_TYPE_CODE);
+ return ((const shared_container_t *)candidate_shared_container)->container;
+ } else {
+ return candidate_shared_container;
+ }
+}
+
+
+/* access to container underneath */
+static inline void *container_mutable_unwrap_shared(
+ void *candidate_shared_container, uint8_t *type) {
+ if (*type == SHARED_CONTAINER_TYPE_CODE) {
+ *type =
+ ((shared_container_t *)candidate_shared_container)->typecode;
+ assert(*type != SHARED_CONTAINER_TYPE_CODE);
+ return ((shared_container_t *)candidate_shared_container)->container;
+ } else {
+ return candidate_shared_container;
+ }
+}
+
+/* access to container underneath and queries its type */
+static inline uint8_t get_container_type(const void *container, uint8_t type) {
+ if (type == SHARED_CONTAINER_TYPE_CODE) {
+ return ((const shared_container_t *)container)->typecode;
+ } else {
+ return type;
+ }
+}
+
+/**
+ * Copies a container, requires a typecode. This allocates new memory, caller
+ * is responsible for deallocation. If the container is not shared, then it is
+ * physically cloned. Shareable containers are not clonable.
+ */
+void *container_clone(const void *container, uint8_t typecode);
+
+/* access to container underneath, cloning it if needed */
+static inline void *get_writable_copy_if_shared(
+ void *candidate_shared_container, uint8_t *type) {
+ if (*type == SHARED_CONTAINER_TYPE_CODE) {
+ return shared_container_extract_copy(
+ (shared_container_t *)candidate_shared_container, type);
+ } else {
+ return candidate_shared_container;
+ }
+}
+
+/**
+ * End of shared container code
+ */
+
+static const char *container_names[] = {"bitset", "array", "run", "shared"};
+static const char *shared_container_names[] = {
+ "bitset (shared)", "array (shared)", "run (shared)"};
+
+// no matter what the initial container was, convert it to a bitset
+// if a new container is produced, caller responsible for freeing the previous
+// one
+// container should not be a shared container
+static inline void *container_to_bitset(void *container, uint8_t typecode) {
+ bitset_container_t *result = NULL;
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return container; // nothing to do
+ case ARRAY_CONTAINER_TYPE_CODE:
+ result =
+ bitset_container_from_array((array_container_t *)container);
+ return result;
+ case RUN_CONTAINER_TYPE_CODE:
+ result = bitset_container_from_run((run_container_t *)container);
+ return result;
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+/**
+ * Get the container name from the typecode
+ */
+static inline const char *get_container_name(uint8_t typecode) {
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return container_names[0];
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return container_names[1];
+ case RUN_CONTAINER_TYPE_CODE:
+ return container_names[2];
+ case SHARED_CONTAINER_TYPE_CODE:
+ return container_names[3];
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return "unknown";
+ }
+}
+
+static inline const char *get_full_container_name(const void *container,
+ uint8_t typecode) {
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return container_names[0];
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return container_names[1];
+ case RUN_CONTAINER_TYPE_CODE:
+ return container_names[2];
+ case SHARED_CONTAINER_TYPE_CODE:
+ switch (((const shared_container_t *)container)->typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return shared_container_names[0];
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return shared_container_names[1];
+ case RUN_CONTAINER_TYPE_CODE:
+ return shared_container_names[2];
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return "unknown";
+ }
+ break;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return "unknown";
+ }
+ __builtin_unreachable();
+ return NULL;
+}
+
+/**
+ * Get the container cardinality (number of elements), requires a typecode
+ */
+static inline int container_get_cardinality(const void *container,
+ uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_cardinality(
+ (const bitset_container_t *)container);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_cardinality(
+ (const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_cardinality(
+ (const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+
+
+// returns true if a container is known to be full. Note that a lazy bitset
+// container
+// might be full without us knowing
+static inline bool container_is_full(const void *container, uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_cardinality(
+ (const bitset_container_t *)container) == (1 << 16);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_cardinality(
+ (const array_container_t *)container) == (1 << 16);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_is_full((const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+static inline int container_shrink_to_fit(void *container, uint8_t typecode) {
+ container = container_mutable_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return 0; // no shrinking possible
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_shrink_to_fit(
+ (array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_shrink_to_fit((run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+
+/**
+ * make a container with a run of ones
+ */
+/* initially always use a run container, even if an array might be
+ * marginally
+ * smaller */
+static inline void *container_range_of_ones(uint32_t range_start,
+ uint32_t range_end,
+ uint8_t *result_type) {
+ assert(range_end >= range_start);
+ uint64_t cardinality = range_end - range_start + 1;
+ if(cardinality <= 2) {
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return array_container_create_range(range_start, range_end);
+ } else {
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return run_container_create_range(range_start, range_end);
+ }
+}
+
+
+/* Create a container with all the values between in [min,max) at a
+ distance k*step from min. */
+static inline void *container_from_range(uint8_t *type, uint32_t min,
+ uint32_t max, uint16_t step) {
+ if (step == 0) return NULL; // being paranoid
+ if (step == 1) {
+ return container_range_of_ones(min,max,type);
+ // Note: the result is not always a run (need to check the cardinality)
+ //*type = RUN_CONTAINER_TYPE_CODE;
+ //return run_container_create_range(min, max);
+ }
+ int size = (max - min + step - 1) / step;
+ if (size <= DEFAULT_MAX_SIZE) { // array container
+ *type = ARRAY_CONTAINER_TYPE_CODE;
+ array_container_t *array = array_container_create_given_capacity(size);
+ array_container_add_from_range(array, min, max, step);
+ assert(array->cardinality == size);
+ return array;
+ } else { // bitset container
+ *type = BITSET_CONTAINER_TYPE_CODE;
+ bitset_container_t *bitset = bitset_container_create();
+ bitset_container_add_from_range(bitset, min, max, step);
+ assert(bitset->cardinality == size);
+ return bitset;
+ }
+}
+
+/**
+ * "repair" the container after lazy operations.
+ */
+static inline void *container_repair_after_lazy(void *container,
+ uint8_t *typecode) {
+ container = get_writable_copy_if_shared(
+ container, typecode); // TODO: this introduces unnecessary cloning
+ void *result = NULL;
+ switch (*typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ ((bitset_container_t *)container)->cardinality =
+ bitset_container_compute_cardinality(
+ (bitset_container_t *)container);
+ if (((bitset_container_t *)container)->cardinality <=
+ DEFAULT_MAX_SIZE) {
+ result = array_container_from_bitset(
+ (const bitset_container_t *)container);
+ bitset_container_free((bitset_container_t *)container);
+ *typecode = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ }
+ return container;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return container; // nothing to do
+ case RUN_CONTAINER_TYPE_CODE:
+ return convert_run_to_efficient_container_and_free(
+ (run_container_t *)container, typecode);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+/**
+ * Writes the underlying array to buf, outputs how many bytes were written.
+ * This is meant to be byte-by-byte compatible with the Java and Go versions of
+ * Roaring.
+ * The number of bytes written should be
+ * container_write(container, buf).
+ *
+ */
+static inline int32_t container_write(const void *container, uint8_t typecode,
+ char *buf) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_write((const bitset_container_t *)container, buf);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_write((const array_container_t *)container, buf);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_write((const run_container_t *)container, buf);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+/**
+ * Get the container size in bytes under portable serialization (see
+ * container_write), requires a
+ * typecode
+ */
+static inline int32_t container_size_in_bytes(const void *container,
+ uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_size_in_bytes(
+ (const bitset_container_t *)container);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_size_in_bytes(
+ (const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_size_in_bytes((const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+/**
+ * print the container (useful for debugging), requires a typecode
+ */
+void container_printf(const void *container, uint8_t typecode);
+
+/**
+ * print the content of the container as a comma-separated list of 32-bit values
+ * starting at base, requires a typecode
+ */
+void container_printf_as_uint32_array(const void *container, uint8_t typecode,
+ uint32_t base);
+
+/**
+ * Checks whether a container is not empty, requires a typecode
+ */
+static inline bool container_nonzero_cardinality(const void *container,
+ uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_const_nonzero_cardinality(
+ (const bitset_container_t *)container);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_nonzero_cardinality(
+ (const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_nonzero_cardinality(
+ (const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+/**
+ * Recover memory from a container, requires a typecode
+ */
+void container_free(void *container, uint8_t typecode);
+
+/**
+ * Convert a container to an array of values, requires a typecode as well as a
+ * "base" (most significant values)
+ * Returns number of ints added.
+ */
+static inline int container_to_uint32_array(uint32_t *output,
+ const void *container,
+ uint8_t typecode, uint32_t base) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_to_uint32_array(
+ output, (const bitset_container_t *)container, base);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_to_uint32_array(
+ output, (const array_container_t *)container, base);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_to_uint32_array(
+ output, (const run_container_t *)container, base);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0; // unreached
+ }
+}
+
+/**
+ * Add a value to a container, requires a typecode, fills in new_typecode and
+ * return (possibly different) container.
+ * This function may allocate a new container, and caller is responsible for
+ * memory deallocation
+ */
+static inline void *container_add(void *container, uint16_t val,
+ uint8_t typecode, uint8_t *new_typecode) {
+ container = get_writable_copy_if_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ bitset_container_set((bitset_container_t *)container, val);
+ *new_typecode = BITSET_CONTAINER_TYPE_CODE;
+ return container;
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ array_container_t *ac = (array_container_t *)container;
+ if (array_container_try_add(ac, val, DEFAULT_MAX_SIZE) != -1) {
+ *new_typecode = ARRAY_CONTAINER_TYPE_CODE;
+ return ac;
+ } else {
+ bitset_container_t* bitset = bitset_container_from_array(ac);
+ bitset_container_add(bitset, val);
+ *new_typecode = BITSET_CONTAINER_TYPE_CODE;
+ return bitset;
+ }
+ } break;
+ case RUN_CONTAINER_TYPE_CODE:
+ // per Java, no container type adjustments are done (revisit?)
+ run_container_add((run_container_t *)container, val);
+ *new_typecode = RUN_CONTAINER_TYPE_CODE;
+ return container;
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Remove a value from a container, requires a typecode, fills in new_typecode
+ * and
+ * return (possibly different) container.
+ * This function may allocate a new container, and caller is responsible for
+ * memory deallocation
+ */
+static inline void *container_remove(void *container, uint16_t val,
+ uint8_t typecode, uint8_t *new_typecode) {
+ container = get_writable_copy_if_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ if (bitset_container_remove((bitset_container_t *)container, val)) {
+ if (bitset_container_cardinality(
+ (bitset_container_t *)container) <= DEFAULT_MAX_SIZE) {
+ *new_typecode = ARRAY_CONTAINER_TYPE_CODE;
+ return array_container_from_bitset(
+ (bitset_container_t *)container);
+ }
+ }
+ *new_typecode = typecode;
+ return container;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ *new_typecode = typecode;
+ array_container_remove((array_container_t *)container, val);
+ return container;
+ case RUN_CONTAINER_TYPE_CODE:
+ // per Java, no container type adjustments are done (revisit?)
+ run_container_remove((run_container_t *)container, val);
+ *new_typecode = RUN_CONTAINER_TYPE_CODE;
+ return container;
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Check whether a value is in a container, requires a typecode
+ */
+static inline bool container_contains(const void *container, uint16_t val,
+ uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_get((const bitset_container_t *)container,
+ val);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_contains(
+ (const array_container_t *)container, val);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_contains((const run_container_t *)container,
+ val);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+/**
+ * Check whether a range of values from range_start (included) to range_end (excluded)
+ * is in a container, requires a typecode
+ */
+static inline bool container_contains_range(const void *container, uint32_t range_start,
+ uint32_t range_end, uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_get_range((const bitset_container_t *)container,
+ range_start, range_end);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_contains_range((const array_container_t *)container,
+ range_start, range_end);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_contains_range((const run_container_t *)container,
+ range_start, range_end);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+int32_t container_serialize(const void *container, uint8_t typecode,
+ char *buf) WARN_UNUSED;
+
+uint32_t container_serialization_len(const void *container, uint8_t typecode);
+
+void *container_deserialize(uint8_t typecode, const char *buf, size_t buf_len);
+
+/**
+ * Returns true if the two containers have the same content. Note that
+ * two containers having different types can be "equal" in this sense.
+ */
+static inline bool container_equals(const void *c1, uint8_t type1,
+ const void *c2, uint8_t type2) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return bitset_container_equals((const bitset_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ return run_container_equals_bitset((const run_container_t *)c2,
+ (const bitset_container_t *)c1);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return run_container_equals_bitset((const run_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ // java would always return false?
+ return array_container_equal_bitset((const array_container_t *)c2,
+ (const bitset_container_t *)c1);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ // java would always return false?
+ return array_container_equal_bitset((const array_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return run_container_equals_array((const run_container_t *)c2,
+ (const array_container_t *)c1);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ return run_container_equals_array((const run_container_t *)c1,
+ (const array_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return array_container_equals((const array_container_t *)c1,
+ (const array_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return run_container_equals((const run_container_t *)c1,
+ (const run_container_t *)c2);
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+/**
+ * Returns true if the container c1 is a subset of the container c2. Note that
+ * c1 can be a subset of c2 even if they have a different type.
+ */
+static inline bool container_is_subset(const void *c1, uint8_t type1,
+ const void *c2, uint8_t type2) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return bitset_container_is_subset((const bitset_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ return bitset_container_is_subset_run((const bitset_container_t *)c1,
+ (const run_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return run_container_is_subset_bitset((const run_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return false; // by construction, size(c1) > size(c2)
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return array_container_is_subset_bitset((const array_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return array_container_is_subset_run((const array_container_t *)c1,
+ (const run_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ return run_container_is_subset_array((const run_container_t *)c1,
+ (const array_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return array_container_is_subset((const array_container_t *)c1,
+ (const array_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return run_container_is_subset((const run_container_t *)c1,
+ (const run_container_t *)c2);
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+// macro-izations possibilities for generic non-inplace binary-op dispatch
+
+/**
+ * Compute intersection between two containers, generate a new container (having
+ * type result_type), requires a typecode. This allocates new memory, caller
+ * is responsible for deallocation.
+ */
+static inline void *container_and(const void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = bitset_bitset_container_intersection(
+ (const bitset_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ array_container_intersection((const array_container_t *)c1,
+ (const array_container_t *)c2,
+ (array_container_t *)result);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ run_container_intersection((const run_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ return convert_run_to_efficient_container_and_free(
+ (run_container_t *)result, result_type);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ array_bitset_container_intersection((const array_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (array_container_t *)result);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ array_bitset_container_intersection((const array_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (array_container_t *)result);
+ return result;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ *result_type = run_bitset_container_intersection(
+ (const run_container_t *)c2,
+ (const bitset_container_t *)c1, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = run_bitset_container_intersection(
+ (const run_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ array_run_container_intersection((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (array_container_t *)result);
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ array_run_container_intersection((const array_container_t *)c2,
+ (const run_container_t *)c1,
+ (array_container_t *)result);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Compute the size of the intersection between two containers.
+ */
+static inline int container_and_cardinality(const void *c1, uint8_t type1,
+ const void *c2, uint8_t type2) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return bitset_container_and_justcard(
+ (const bitset_container_t *)c1, (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return array_container_intersection_cardinality(
+ (const array_container_t *)c1, (const array_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return run_container_intersection_cardinality(
+ (const run_container_t *)c1, (const run_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return array_bitset_container_intersection_cardinality(
+ (const array_container_t *)c2, (const bitset_container_t *)c1);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return array_bitset_container_intersection_cardinality(
+ (const array_container_t *)c1, (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ return run_bitset_container_intersection_cardinality(
+ (const run_container_t *)c2, (const bitset_container_t *)c1);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return run_bitset_container_intersection_cardinality(
+ (const run_container_t *)c1, (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return array_run_container_intersection_cardinality(
+ (const array_container_t *)c1, (const run_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ return array_run_container_intersection_cardinality(
+ (const array_container_t *)c2, (const run_container_t *)c1);
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0;
+ }
+}
+
+/**
+ * Check whether two containers intersect.
+ */
+static inline bool container_intersect(const void *c1, uint8_t type1, const void *c2,
+ uint8_t type2) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return bitset_container_intersect(
+ (const bitset_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return array_container_intersect((const array_container_t *)c1,
+ (const array_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return run_container_intersect((const run_container_t *)c1,
+ (const run_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ return array_bitset_container_intersect((const array_container_t *)c2,
+ (const bitset_container_t *)c1);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return array_bitset_container_intersect((const array_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ return run_bitset_container_intersect(
+ (const run_container_t *)c2,
+ (const bitset_container_t *)c1);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ return run_bitset_container_intersect(
+ (const run_container_t *)c1,
+ (const bitset_container_t *)c2);
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ return array_run_container_intersect((const array_container_t *)c1,
+ (const run_container_t *)c2);
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ return array_run_container_intersect((const array_container_t *)c2,
+ (const run_container_t *)c1);
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return 0;
+ }
+}
+
+/**
+ * Compute intersection between two containers, with result in the first
+ container if possible. If the returned pointer is identical to c1,
+ then the container has been modified. If the returned pointer is different
+ from c1, then a new container has been created and the caller is responsible
+ for freeing it.
+ The type of the first container may change. Returns the modified
+ (and possibly new) container.
+*/
+static inline void *container_iand(void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = get_writable_copy_if_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type =
+ bitset_bitset_container_intersection_inplace(
+ (bitset_container_t *)c1, (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ array_container_intersection_inplace((array_container_t *)c1,
+ (const array_container_t *)c2);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return c1;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ run_container_intersection((const run_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ // as of January 2016, Java code used non-in-place intersection for
+ // two runcontainers
+ return convert_run_to_efficient_container_and_free(
+ (run_container_t *)result, result_type);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ // c1 is a bitmap so no inplace possible
+ result = array_container_create();
+ array_bitset_container_intersection((const array_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (array_container_t *)result);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ array_bitset_container_intersection(
+ (const array_container_t *)c1, (const bitset_container_t *)c2,
+ (array_container_t *)c1); // allowed
+ return c1;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ // will attempt in-place computation
+ *result_type = run_bitset_container_intersection(
+ (const run_container_t *)c2,
+ (const bitset_container_t *)c1, &c1)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return c1;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = run_bitset_container_intersection(
+ (const run_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ array_run_container_intersection((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (array_container_t *)result);
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE; // never bitset
+ array_run_container_intersection((const array_container_t *)c2,
+ (const run_container_t *)c1,
+ (array_container_t *)result);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Compute union between two containers, generate a new container (having type
+ * result_type), requires a typecode. This allocates new memory, caller
+ * is responsible for deallocation.
+ */
+static inline void *container_or(const void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ bitset_container_or((const bitset_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_union(
+ (const array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ run_container_union((const run_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // todo: could be optimized since will never convert to array
+ result = convert_run_to_efficient_container_and_free(
+ (run_container_t *)result, (uint8_t *)result_type);
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ array_bitset_container_union((const array_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ array_bitset_container_union((const array_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = run_container_create();
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ run_container_copy((const run_container_t *)c2,
+ (run_container_t *)result);
+ return result;
+ }
+ result = bitset_container_create();
+ run_bitset_container_union((const run_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c1)) {
+ result = run_container_create();
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ run_container_copy((const run_container_t *)c1,
+ (run_container_t *)result);
+ return result;
+ }
+ result = bitset_container_create();
+ run_bitset_container_union((const run_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_union((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ result = convert_run_to_efficient_container_and_free(
+ (run_container_t *)result, (uint8_t *)result_type);
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_union((const array_container_t *)c2,
+ (const run_container_t *)c1,
+ (run_container_t *)result);
+ result = convert_run_to_efficient_container_and_free(
+ (run_container_t *)result, (uint8_t *)result_type);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL; // unreached
+ }
+}
+
+/**
+ * Compute union between two containers, generate a new container (having type
+ * result_type), requires a typecode. This allocates new memory, caller
+ * is responsible for deallocation.
+ *
+ * This lazy version delays some operations such as the maintenance of the
+ * cardinality. It requires repair later on the generated containers.
+ */
+static inline void *container_lazy_or(const void *c1, uint8_t type1,
+ const void *c2, uint8_t type2,
+ uint8_t *result_type) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ bitset_container_or_nocard(
+ (const bitset_container_t *)c1, (const bitset_container_t *)c2,
+ (bitset_container_t *)result); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_lazy_union(
+ (const array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ run_container_union((const run_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // we are being lazy
+ result = convert_run_to_efficient_container(
+ (run_container_t *)result, result_type);
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ array_bitset_container_lazy_union(
+ (const array_container_t *)c2, (const bitset_container_t *)c1,
+ (bitset_container_t *)result); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ array_bitset_container_lazy_union(
+ (const array_container_t *)c1, (const bitset_container_t *)c2,
+ (bitset_container_t *)result); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = run_container_create();
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ run_container_copy((const run_container_t *)c2,
+ (run_container_t *)result);
+ return result;
+ }
+ result = bitset_container_create();
+ run_bitset_container_lazy_union(
+ (const run_container_t *)c2, (const bitset_container_t *)c1,
+ (bitset_container_t *)result); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c1)) {
+ result = run_container_create();
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ run_container_copy((const run_container_t *)c1,
+ (run_container_t *)result);
+ return result;
+ }
+ result = bitset_container_create();
+ run_bitset_container_lazy_union(
+ (const run_container_t *)c1, (const bitset_container_t *)c2,
+ (bitset_container_t *)result); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_union((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // next line skipped since we are lazy
+ // result = convert_run_to_efficient_container(result, result_type);
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_union(
+ (const array_container_t *)c2, (const run_container_t *)c1,
+ (run_container_t *)result); // TODO make lazy
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // next line skipped since we are lazy
+ // result = convert_run_to_efficient_container(result, result_type);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL; // unreached
+ }
+}
+
+/**
+ * Compute the union between two containers, with result in the first container.
+ * If the returned pointer is identical to c1, then the container has been
+ * modified.
+ * If the returned pointer is different from c1, then a new container has been
+ * created and the caller is responsible for freeing it.
+ * The type of the first container may change. Returns the modified
+ * (and possibly new) container
+*/
+static inline void *container_ior(void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = get_writable_copy_if_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ bitset_container_or((const bitset_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)c1);
+#ifdef OR_BITSET_CONVERSION_TO_FULL
+ if (((bitset_container_t *)c1)->cardinality ==
+ (1 << 16)) { // we convert
+ result = run_container_create_range(0, (1 << 16));
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return result;
+ }
+#endif
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return c1;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_inplace_union(
+ (array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ if((result == NULL)
+ && (*result_type == ARRAY_CONTAINER_TYPE_CODE)) {
+ return c1; // the computation was done in-place!
+ }
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ run_container_union_inplace((run_container_t *)c1,
+ (const run_container_t *)c2);
+ return convert_run_to_efficient_container((run_container_t *)c1,
+ result_type);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ array_bitset_container_union((const array_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (bitset_container_t *)c1);
+ *result_type = BITSET_CONTAINER_TYPE_CODE; // never array
+ return c1;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ // c1 is an array, so no in-place possible
+ result = bitset_container_create();
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ array_bitset_container_union((const array_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = run_container_create();
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ run_container_copy((const run_container_t *)c2,
+ (run_container_t *)result);
+ return result;
+ }
+ run_bitset_container_union((const run_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (bitset_container_t *)c1); // allowed
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return c1;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c1)) {
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+
+ return c1;
+ }
+ result = bitset_container_create();
+ run_bitset_container_union((const run_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_union((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ result = convert_run_to_efficient_container_and_free(
+ (run_container_t *)result, result_type);
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ array_run_container_inplace_union((const array_container_t *)c2,
+ (run_container_t *)c1);
+ c1 = convert_run_to_efficient_container((run_container_t *)c1,
+ result_type);
+ return c1;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Compute the union between two containers, with result in the first container.
+ * If the returned pointer is identical to c1, then the container has been
+ * modified.
+ * If the returned pointer is different from c1, then a new container has been
+ * created and the caller is responsible for freeing it.
+ * The type of the first container may change. Returns the modified
+ * (and possibly new) container
+ *
+ * This lazy version delays some operations such as the maintenance of the
+ * cardinality. It requires repair later on the generated containers.
+*/
+static inline void *container_lazy_ior(void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ assert(type1 != SHARED_CONTAINER_TYPE_CODE);
+ // c1 = get_writable_copy_if_shared(c1,&type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+#ifdef LAZY_OR_BITSET_CONVERSION_TO_FULL
+ // if we have two bitsets, we might as well compute the cardinality
+ bitset_container_or((const bitset_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)c1);
+ // it is possible that two bitsets can lead to a full container
+ if (((bitset_container_t *)c1)->cardinality ==
+ (1 << 16)) { // we convert
+ result = run_container_create_range(0, (1 << 16));
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return result;
+ }
+#else
+ bitset_container_or_nocard((const bitset_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)c1);
+
+#endif
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return c1;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_lazy_inplace_union(
+ (array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ if((result == NULL)
+ && (*result_type == ARRAY_CONTAINER_TYPE_CODE)) {
+ return c1; // the computation was done in-place!
+ }
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ run_container_union_inplace((run_container_t *)c1,
+ (const run_container_t *)c2);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return convert_run_to_efficient_container((run_container_t *)c1,
+ result_type);
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ array_bitset_container_lazy_union(
+ (const array_container_t *)c2, (const bitset_container_t *)c1,
+ (bitset_container_t *)c1); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE; // never array
+ return c1;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ // c1 is an array, so no in-place possible
+ result = bitset_container_create();
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ array_bitset_container_lazy_union(
+ (const array_container_t *)c1, (const bitset_container_t *)c2,
+ (bitset_container_t *)result); // is lazy
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = run_container_create();
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ run_container_copy((const run_container_t *)c2,
+ (run_container_t *)result);
+ return result;
+ }
+ run_bitset_container_lazy_union(
+ (const run_container_t *)c2, (const bitset_container_t *)c1,
+ (bitset_container_t *)c1); // allowed // lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return c1;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c1)) {
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return c1;
+ }
+ result = bitset_container_create();
+ run_bitset_container_lazy_union(
+ (const run_container_t *)c1, (const bitset_container_t *)c2,
+ (bitset_container_t *)result); // lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_union((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // next line skipped since we are lazy
+ // result = convert_run_to_efficient_container_and_free(result,
+ // result_type);
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ array_run_container_inplace_union((const array_container_t *)c2,
+ (run_container_t *)c1);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // next line skipped since we are lazy
+ // result = convert_run_to_efficient_container_and_free(result,
+ // result_type);
+ return c1;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Compute symmetric difference (xor) between two containers, generate a new
+ * container (having type result_type), requires a typecode. This allocates new
+ * memory, caller is responsible for deallocation.
+ */
+static inline void *container_xor(const void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = bitset_bitset_container_xor(
+ (const bitset_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_xor(
+ (const array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ *result_type =
+ run_run_container_xor((const run_container_t *)c1,
+ (const run_container_t *)c2, &result);
+ return result;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_bitset_container_xor(
+ (const array_container_t *)c2,
+ (const bitset_container_t *)c1, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = array_bitset_container_xor(
+ (const array_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ *result_type = run_bitset_container_xor(
+ (const run_container_t *)c2,
+ (const bitset_container_t *)c1, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+
+ *result_type = run_bitset_container_xor(
+ (const run_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ *result_type =
+ array_run_container_xor((const array_container_t *)c1,
+ (const run_container_t *)c2, &result);
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ *result_type =
+ array_run_container_xor((const array_container_t *)c2,
+ (const run_container_t *)c1, &result);
+ return result;
+
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL; // unreached
+ }
+}
+
+/**
+ * Compute xor between two containers, generate a new container (having type
+ * result_type), requires a typecode. This allocates new memory, caller
+ * is responsible for deallocation.
+ *
+ * This lazy version delays some operations such as the maintenance of the
+ * cardinality. It requires repair later on the generated containers.
+ */
+static inline void *container_lazy_xor(const void *c1, uint8_t type1,
+ const void *c2, uint8_t type2,
+ uint8_t *result_type) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ bitset_container_xor_nocard(
+ (const bitset_container_t *)c1, (const bitset_container_t *)c2,
+ (bitset_container_t *)result); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_lazy_xor(
+ (const array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ // nothing special done yet.
+ *result_type =
+ run_run_container_xor((const run_container_t *)c1,
+ (const run_container_t *)c2, &result);
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ array_bitset_container_lazy_xor((const array_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (bitset_container_t *)result);
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ array_bitset_container_lazy_xor((const array_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ run_bitset_container_lazy_xor((const run_container_t *)c2,
+ (const bitset_container_t *)c1,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = bitset_container_create();
+ run_bitset_container_lazy_xor((const run_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)result);
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return result;
+
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_lazy_xor((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (run_container_t *)result);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // next line skipped since we are lazy
+ // result = convert_run_to_efficient_container(result, result_type);
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ result = run_container_create();
+ array_run_container_lazy_xor((const array_container_t *)c2,
+ (const run_container_t *)c1,
+ (run_container_t *)result);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ // next line skipped since we are lazy
+ // result = convert_run_to_efficient_container(result, result_type);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL; // unreached
+ }
+}
+
+/**
+ * Compute the xor between two containers, with result in the first container.
+ * If the returned pointer is identical to c1, then the container has been
+ * modified.
+ * If the returned pointer is different from c1, then a new container has been
+ * created and the caller is responsible for freeing it.
+ * The type of the first container may change. Returns the modified
+ * (and possibly new) container
+*/
+static inline void *container_ixor(void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = get_writable_copy_if_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = bitset_bitset_container_ixor(
+ (bitset_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = array_array_container_ixor(
+ (array_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ *result_type = run_run_container_ixor(
+ (run_container_t *)c1, (const run_container_t *)c2, &result);
+ return result;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = bitset_array_container_ixor(
+ (bitset_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = array_bitset_container_ixor(
+ (array_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+
+ return result;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ *result_type =
+ bitset_run_container_ixor((bitset_container_t *)c1,
+ (const run_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = run_bitset_container_ixor(
+ (run_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+
+ return result;
+
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ *result_type = array_run_container_ixor(
+ (array_container_t *)c1, (const run_container_t *)c2, &result);
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = run_array_container_ixor(
+ (run_container_t *)c1, (const array_container_t *)c2, &result);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Compute the xor between two containers, with result in the first container.
+ * If the returned pointer is identical to c1, then the container has been
+ * modified.
+ * If the returned pointer is different from c1, then a new container has been
+ * created and the caller is responsible for freeing it.
+ * The type of the first container may change. Returns the modified
+ * (and possibly new) container
+ *
+ * This lazy version delays some operations such as the maintenance of the
+ * cardinality. It requires repair later on the generated containers.
+*/
+static inline void *container_lazy_ixor(void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ assert(type1 != SHARED_CONTAINER_TYPE_CODE);
+ // c1 = get_writable_copy_if_shared(c1,&type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ bitset_container_xor_nocard((bitset_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (bitset_container_t *)c1); // is lazy
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return c1;
+ // TODO: other cases being lazy, esp. when we know inplace not likely
+ // could see the corresponding code for union
+ default:
+ // we may have a dirty bitset (without a precomputed cardinality) and
+ // calling container_ixor on it might be unsafe.
+ if( (type1 == BITSET_CONTAINER_TYPE_CODE)
+ && (((const bitset_container_t *)c1)->cardinality == BITSET_UNKNOWN_CARDINALITY)) {
+ ((bitset_container_t *)c1)->cardinality = bitset_container_compute_cardinality((bitset_container_t *)c1);
+ }
+ return container_ixor(c1, type1, c2, type2, result_type);
+ }
+}
+
+/**
+ * Compute difference (andnot) between two containers, generate a new
+ * container (having type result_type), requires a typecode. This allocates new
+ * memory, caller is responsible for deallocation.
+ */
+static inline void *container_andnot(const void *c1, uint8_t type1,
+ const void *c2, uint8_t type2,
+ uint8_t *result_type) {
+ c1 = container_unwrap_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = bitset_bitset_container_andnot(
+ (const bitset_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ array_array_container_andnot((const array_container_t *)c1,
+ (const array_container_t *)c2,
+ (array_container_t *)result);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ }
+ *result_type =
+ run_run_container_andnot((const run_container_t *)c1,
+ (const run_container_t *)c2, &result);
+ return result;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = bitset_array_container_andnot(
+ (const bitset_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ result = array_container_create();
+ array_bitset_container_andnot((const array_container_t *)c1,
+ (const bitset_container_t *)c2,
+ (array_container_t *)result);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ }
+ *result_type = bitset_run_container_andnot(
+ (const bitset_container_t *)c1,
+ (const run_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+
+ *result_type = run_bitset_container_andnot(
+ (const run_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ if (run_container_is_full((const run_container_t *)c2)) {
+ result = array_container_create();
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ }
+ result = array_container_create();
+ array_run_container_andnot((const array_container_t *)c1,
+ (const run_container_t *)c2,
+ (array_container_t *)result);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = run_array_container_andnot(
+ (const run_container_t *)c1, (const array_container_t *)c2,
+ &result);
+ return result;
+
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL; // unreached
+ }
+}
+
+/**
+ * Compute the andnot between two containers, with result in the first
+ * container.
+ * If the returned pointer is identical to c1, then the container has been
+ * modified.
+ * If the returned pointer is different from c1, then a new container has been
+ * created and the caller is responsible for freeing it.
+ * The type of the first container may change. Returns the modified
+ * (and possibly new) container
+*/
+static inline void *container_iandnot(void *c1, uint8_t type1, const void *c2,
+ uint8_t type2, uint8_t *result_type) {
+ c1 = get_writable_copy_if_shared(c1, &type1);
+ c2 = container_unwrap_shared(c2, &type2);
+ void *result = NULL;
+ switch (CONTAINER_PAIR(type1, type2)) {
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = bitset_bitset_container_iandnot(
+ (bitset_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ array_array_container_iandnot((array_container_t *)c1,
+ (const array_container_t *)c2);
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ return c1;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ *result_type = run_run_container_iandnot(
+ (run_container_t *)c1, (const run_container_t *)c2, &result);
+ return result;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = bitset_array_container_iandnot(
+ (bitset_container_t *)c1,
+ (const array_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+
+ array_bitset_container_iandnot((array_container_t *)c1,
+ (const bitset_container_t *)c2);
+ return c1;
+
+ case CONTAINER_PAIR(BITSET_CONTAINER_TYPE_CODE,
+ RUN_CONTAINER_TYPE_CODE):
+ *result_type = bitset_run_container_iandnot(
+ (bitset_container_t *)c1,
+ (const run_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+
+ return result;
+
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE,
+ BITSET_CONTAINER_TYPE_CODE):
+ *result_type = run_bitset_container_iandnot(
+ (run_container_t *)c1,
+ (const bitset_container_t *)c2, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+
+ return result;
+
+ case CONTAINER_PAIR(ARRAY_CONTAINER_TYPE_CODE, RUN_CONTAINER_TYPE_CODE):
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ array_run_container_iandnot((array_container_t *)c1,
+ (const run_container_t *)c2);
+ return c1;
+ case CONTAINER_PAIR(RUN_CONTAINER_TYPE_CODE, ARRAY_CONTAINER_TYPE_CODE):
+ *result_type = run_array_container_iandnot(
+ (run_container_t *)c1, (const array_container_t *)c2, &result);
+ return result;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * Visit all values x of the container once, passing (base+x,ptr)
+ * to iterator. You need to specify a container and its type.
+ * Returns true if the iteration should continue.
+ */
+static inline bool container_iterate(const void *container, uint8_t typecode,
+ uint32_t base, roaring_iterator iterator,
+ void *ptr) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_iterate(
+ (const bitset_container_t *)container, base, iterator, ptr);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_iterate((const array_container_t *)container,
+ base, iterator, ptr);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_iterate((const run_container_t *)container,
+ base, iterator, ptr);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+static inline bool container_iterate64(const void *container, uint8_t typecode,
+ uint32_t base,
+ roaring_iterator64 iterator,
+ uint64_t high_bits, void *ptr) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_iterate64(
+ (const bitset_container_t *)container, base, iterator,
+ high_bits, ptr);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_iterate64(
+ (const array_container_t *)container, base, iterator, high_bits,
+ ptr);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_iterate64((const run_container_t *)container,
+ base, iterator, high_bits, ptr);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+static inline void *container_not(const void *c, uint8_t typ,
+ uint8_t *result_type) {
+ c = container_unwrap_shared(c, &typ);
+ void *result = NULL;
+ switch (typ) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ *result_type = bitset_container_negation(
+ (const bitset_container_t *)c, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ result = bitset_container_create();
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ array_container_negation((const array_container_t *)c,
+ (bitset_container_t *)result);
+ return result;
+ case RUN_CONTAINER_TYPE_CODE:
+ *result_type =
+ run_container_negation((const run_container_t *)c, &result);
+ return result;
+
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+static inline void *container_not_range(const void *c, uint8_t typ,
+ uint32_t range_start,
+ uint32_t range_end,
+ uint8_t *result_type) {
+ c = container_unwrap_shared(c, &typ);
+ void *result = NULL;
+ switch (typ) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ *result_type =
+ bitset_container_negation_range((const bitset_container_t *)c,
+ range_start, range_end, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ *result_type =
+ array_container_negation_range((const array_container_t *)c,
+ range_start, range_end, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case RUN_CONTAINER_TYPE_CODE:
+ *result_type = run_container_negation_range(
+ (const run_container_t *)c, range_start, range_end, &result);
+ return result;
+
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+static inline void *container_inot(void *c, uint8_t typ, uint8_t *result_type) {
+ c = get_writable_copy_if_shared(c, &typ);
+ void *result = NULL;
+ switch (typ) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ *result_type = bitset_container_negation_inplace(
+ (bitset_container_t *)c, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ // will never be inplace
+ result = bitset_container_create();
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ array_container_negation((array_container_t *)c,
+ (bitset_container_t *)result);
+ array_container_free((array_container_t *)c);
+ return result;
+ case RUN_CONTAINER_TYPE_CODE:
+ *result_type =
+ run_container_negation_inplace((run_container_t *)c, &result);
+ return result;
+
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+static inline void *container_inot_range(void *c, uint8_t typ,
+ uint32_t range_start,
+ uint32_t range_end,
+ uint8_t *result_type) {
+ c = get_writable_copy_if_shared(c, &typ);
+ void *result = NULL;
+ switch (typ) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ *result_type =
+ bitset_container_negation_range_inplace(
+ (bitset_container_t *)c, range_start, range_end, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case ARRAY_CONTAINER_TYPE_CODE:
+ *result_type =
+ array_container_negation_range_inplace(
+ (array_container_t *)c, range_start, range_end, &result)
+ ? BITSET_CONTAINER_TYPE_CODE
+ : ARRAY_CONTAINER_TYPE_CODE;
+ return result;
+ case RUN_CONTAINER_TYPE_CODE:
+ *result_type = run_container_negation_range_inplace(
+ (run_container_t *)c, range_start, range_end, &result);
+ return result;
+
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return NULL;
+ }
+}
+
+/**
+ * If the element of given rank is in this container, supposing that
+ * the first
+ * element has rank start_rank, then the function returns true and
+ * sets element
+ * accordingly.
+ * Otherwise, it returns false and update start_rank.
+ */
+static inline bool container_select(const void *container, uint8_t typecode,
+ uint32_t *start_rank, uint32_t rank,
+ uint32_t *element) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_select((const bitset_container_t *)container,
+ start_rank, rank, element);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_select((const array_container_t *)container,
+ start_rank, rank, element);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_select((const run_container_t *)container,
+ start_rank, rank, element);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+static inline uint16_t container_maximum(const void *container,
+ uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_maximum((const bitset_container_t *)container);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_maximum((const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_maximum((const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+static inline uint16_t container_minimum(const void *container,
+ uint8_t typecode) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_minimum((const bitset_container_t *)container);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_minimum((const array_container_t *)container);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_minimum((const run_container_t *)container);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+// number of values smaller or equal to x
+static inline int container_rank(const void *container, uint8_t typecode,
+ uint16_t x) {
+ container = container_unwrap_shared(container, &typecode);
+ switch (typecode) {
+ case BITSET_CONTAINER_TYPE_CODE:
+ return bitset_container_rank((const bitset_container_t *)container, x);
+ case ARRAY_CONTAINER_TYPE_CODE:
+ return array_container_rank((const array_container_t *)container, x);
+ case RUN_CONTAINER_TYPE_CODE:
+ return run_container_rank((const run_container_t *)container, x);
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ assert(false);
+ __builtin_unreachable();
+ return false;
+ }
+}
+
+/**
+ * Add all values in range [min, max] to a given container.
+ *
+ * If the returned pointer is different from $container, then a new container
+ * has been created and the caller is responsible for freeing it.
+ * The type of the first container may change. Returns the modified
+ * (and possibly new) container.
+ */
+static inline void *container_add_range(void *container, uint8_t type,
+ uint32_t min, uint32_t max,
+ uint8_t *result_type) {
+ // NB: when selecting new container type, we perform only inexpensive checks
+ switch (type) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ bitset_container_t *bitset = (bitset_container_t *) container;
+
+ int32_t union_cardinality = 0;
+ union_cardinality += bitset->cardinality;
+ union_cardinality += max - min + 1;
+ union_cardinality -= bitset_lenrange_cardinality(bitset->array, min, max-min);
+
+ if (union_cardinality == INT32_C(0x10000)) {
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return run_container_create_range(0, INT32_C(0x10000));
+ } else {
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ bitset_set_lenrange(bitset->array, min, max - min);
+ bitset->cardinality = union_cardinality;
+ return bitset;
+ }
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ array_container_t *array = (array_container_t *) container;
+
+ int32_t nvals_greater = count_greater(array->array, array->cardinality, max);
+ int32_t nvals_less = count_less(array->array, array->cardinality - nvals_greater, min);
+ int32_t union_cardinality = nvals_less + (max - min + 1) + nvals_greater;
+
+ if (union_cardinality == INT32_C(0x10000)) {
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return run_container_create_range(0, INT32_C(0x10000));
+ } else if (union_cardinality <= DEFAULT_MAX_SIZE) {
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ array_container_add_range_nvals(array, min, max, nvals_less, nvals_greater);
+ return array;
+ } else {
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ bitset_container_t *bitset = bitset_container_from_array(array);
+ bitset_set_lenrange(bitset->array, min, max - min);
+ bitset->cardinality = union_cardinality;
+ return bitset;
+ }
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ run_container_t *run = (run_container_t *) container;
+
+ int32_t nruns_greater = rle16_count_greater(run->runs, run->n_runs, max);
+ int32_t nruns_less = rle16_count_less(run->runs, run->n_runs - nruns_greater, min);
+
+ int32_t run_size_bytes = (nruns_less + 1 + nruns_greater) * sizeof(rle16_t);
+ int32_t bitset_size_bytes = BITSET_CONTAINER_SIZE_IN_WORDS * sizeof(uint64_t);
+
+ if (run_size_bytes <= bitset_size_bytes) {
+ run_container_add_range_nruns(run, min, max, nruns_less, nruns_greater);
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return run;
+ } else {
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return bitset_container_from_run_range(run, min, max);
+ }
+ }
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ __builtin_unreachable();
+ }
+}
+
+/*
+ * Removes all elements in range [min, max].
+ * Returns one of:
+ * - NULL if no elements left
+ * - pointer to the original container
+ * - pointer to a newly-allocated container (if it is more efficient)
+ *
+ * If the returned pointer is different from $container, then a new container
+ * has been created and the caller is responsible for freeing the original container.
+ */
+static inline void *container_remove_range(void *container, uint8_t type,
+ uint32_t min, uint32_t max,
+ uint8_t *result_type) {
+ switch (type) {
+ case BITSET_CONTAINER_TYPE_CODE: {
+ bitset_container_t *bitset = (bitset_container_t *) container;
+
+ int32_t result_cardinality = bitset->cardinality -
+ bitset_lenrange_cardinality(bitset->array, min, max-min);
+
+ if (result_cardinality == 0) {
+ return NULL;
+ } else if (result_cardinality < DEFAULT_MAX_SIZE) {
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ bitset_reset_range(bitset->array, min, max+1);
+ bitset->cardinality = result_cardinality;
+ return array_container_from_bitset(bitset);
+ } else {
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ bitset_reset_range(bitset->array, min, max+1);
+ bitset->cardinality = result_cardinality;
+ return bitset;
+ }
+ }
+ case ARRAY_CONTAINER_TYPE_CODE: {
+ array_container_t *array = (array_container_t *) container;
+
+ int32_t nvals_greater = count_greater(array->array, array->cardinality, max);
+ int32_t nvals_less = count_less(array->array, array->cardinality - nvals_greater, min);
+ int32_t result_cardinality = nvals_less + nvals_greater;
+
+ if (result_cardinality == 0) {
+ return NULL;
+ } else {
+ *result_type = ARRAY_CONTAINER_TYPE_CODE;
+ array_container_remove_range(array, nvals_less,
+ array->cardinality - result_cardinality);
+ return array;
+ }
+ }
+ case RUN_CONTAINER_TYPE_CODE: {
+ run_container_t *run = (run_container_t *) container;
+
+ if (run->n_runs == 0) {
+ return NULL;
+ }
+ if (min <= run_container_minimum(run) && max >= run_container_maximum(run)) {
+ return NULL;
+ }
+
+ run_container_remove_range(run, min, max);
+
+ if (run_container_serialized_size_in_bytes(run->n_runs) <=
+ bitset_container_serialized_size_in_bytes()) {
+ *result_type = RUN_CONTAINER_TYPE_CODE;
+ return run;
+ } else {
+ *result_type = BITSET_CONTAINER_TYPE_CODE;
+ return bitset_container_from_run(run);
+ }
+ }
+ case SHARED_CONTAINER_TYPE_CODE:
+ default:
+ __builtin_unreachable();
+ }
+}
+
+#endif
+/* end file include/roaring/containers/containers.h */
+/* begin file include/roaring/roaring_array.h */
+#ifndef INCLUDE_ROARING_ARRAY_H
+#define INCLUDE_ROARING_ARRAY_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+
+#define MAX_CONTAINERS 65536
+
+#define SERIALIZATION_ARRAY_UINT32 1
+#define SERIALIZATION_CONTAINER 2
+
+#define ROARING_FLAG_COW UINT8_C(0x1)
+#define ROARING_FLAG_FROZEN UINT8_C(0x2)
+
+enum {
+ SERIAL_COOKIE_NO_RUNCONTAINER = 12346,
+ SERIAL_COOKIE = 12347,
+ FROZEN_COOKIE = 13766,
+ NO_OFFSET_THRESHOLD = 4
+};
+
+/**
+ * Roaring arrays are array-based key-value pairs having containers as values
+ * and 16-bit integer keys. A roaring bitmap might be implemented as such.
+ */
+
+// parallel arrays. Element sizes quite different.
+// Alternative is array
+// of structs. Which would have better
+// cache performance through binary searches?
+
+typedef struct roaring_array_s {
+ int32_t size;
+ int32_t allocation_size;
+ void **containers;
+ uint16_t *keys;
+ uint8_t *typecodes;
+ uint8_t flags;
+} roaring_array_t;
+
+/**
+ * Create a new roaring array
+ */
+roaring_array_t *ra_create(void);
+
+/**
+ * Initialize an existing roaring array with the specified capacity (in number
+ * of containers)
+ */
+bool ra_init_with_capacity(roaring_array_t *new_ra, uint32_t cap);
+
+/**
+ * Initialize with zero capacity
+ */
+void ra_init(roaring_array_t *t);
+
+/**
+ * Copies this roaring array, we assume that dest is not initialized
+ */
+bool ra_copy(const roaring_array_t *source, roaring_array_t *dest,
+ bool copy_on_write);
+
+/*
+ * Shrinks the capacity, returns the number of bytes saved.
+ */
+int ra_shrink_to_fit(roaring_array_t *ra);
+
+/**
+ * Copies this roaring array, we assume that dest is initialized
+ */
+bool ra_overwrite(const roaring_array_t *source, roaring_array_t *dest,
+ bool copy_on_write);
+
+/**
+ * Frees the memory used by a roaring array
+ */
+void ra_clear(roaring_array_t *r);
+
+/**
+ * Frees the memory used by a roaring array, but does not free the containers
+ */
+void ra_clear_without_containers(roaring_array_t *r);
+
+/**
+ * Frees just the containers
+ */
+void ra_clear_containers(roaring_array_t *ra);
+
+/**
+ * Get the index corresponding to a 16-bit key
+ */
+static inline int32_t ra_get_index(const roaring_array_t *ra, uint16_t x) {
+ if ((ra->size == 0) || ra->keys[ra->size - 1] == x) return ra->size - 1;
+ return binarySearch(ra->keys, (int32_t)ra->size, x);
+}
+
+/**
+ * Retrieves the container at index i, filling in the typecode
+ */
+static inline void *ra_get_container_at_index(const roaring_array_t *ra, uint16_t i,
+ uint8_t *typecode) {
+ *typecode = ra->typecodes[i];
+ return ra->containers[i];
+}
+
+/**
+ * Retrieves the key at index i
+ */
+uint16_t ra_get_key_at_index(const roaring_array_t *ra, uint16_t i);
+
+/**
+ * Add a new key-value pair at index i
+ */
+void ra_insert_new_key_value_at(roaring_array_t *ra, int32_t i, uint16_t key,
+ void *container, uint8_t typecode);
+
+/**
+ * Append a new key-value pair
+ */
+void ra_append(roaring_array_t *ra, uint16_t s, void *c, uint8_t typecode);
+
+/**
+ * Append a new key-value pair to ra, cloning (in COW sense) a value from sa
+ * at index index
+ */
+void ra_append_copy(roaring_array_t *ra, const roaring_array_t *sa,
+ uint16_t index, bool copy_on_write);
+
+/**
+ * Append new key-value pairs to ra, cloning (in COW sense) values from sa
+ * at indexes
+ * [start_index, end_index)
+ */
+void ra_append_copy_range(roaring_array_t *ra, const roaring_array_t *sa,
+ int32_t start_index, int32_t end_index,
+ bool copy_on_write);
+
+/** appends from sa to ra, ending with the greatest key that is
+ * is less or equal stopping_key
+ */
+void ra_append_copies_until(roaring_array_t *ra, const roaring_array_t *sa,
+ uint16_t stopping_key, bool copy_on_write);
+
+/** appends from sa to ra, starting with the smallest key that is
+ * is strictly greater than before_start
+ */
+
+void ra_append_copies_after(roaring_array_t *ra, const roaring_array_t *sa,
+ uint16_t before_start, bool copy_on_write);
+
+/**
+ * Move the key-value pairs to ra from sa at indexes
+ * [start_index, end_index), old array should not be freed
+ * (use ra_clear_without_containers)
+ **/
+void ra_append_move_range(roaring_array_t *ra, roaring_array_t *sa,
+ int32_t start_index, int32_t end_index);
+/**
+ * Append new key-value pairs to ra, from sa at indexes
+ * [start_index, end_index)
+ */
+void ra_append_range(roaring_array_t *ra, roaring_array_t *sa,
+ int32_t start_index, int32_t end_index,
+ bool copy_on_write);
+
+/**
+ * Set the container at the corresponding index using the specified
+ * typecode.
+ */
+static inline void ra_set_container_at_index(const roaring_array_t *ra, int32_t i,
+ void *c, uint8_t typecode) {
+ assert(i < ra->size);
+ ra->containers[i] = c;
+ ra->typecodes[i] = typecode;
+}
+
+/**
+ * If needed, increase the capacity of the array so that it can fit k values
+ * (at
+ * least);
+ */
+bool extend_array(roaring_array_t *ra, int32_t k);
+
+static inline int32_t ra_get_size(const roaring_array_t *ra) { return ra->size; }
+
+static inline int32_t ra_advance_until(const roaring_array_t *ra, uint16_t x,
+ int32_t pos) {
+ return advanceUntil(ra->keys, pos, ra->size, x);
+}
+
+int32_t ra_advance_until_freeing(roaring_array_t *ra, uint16_t x, int32_t pos);
+
+void ra_downsize(roaring_array_t *ra, int32_t new_length);
+
+static inline void ra_replace_key_and_container_at_index(roaring_array_t *ra,
+ int32_t i, uint16_t key,
+ void *c, uint8_t typecode) {
+ assert(i < ra->size);
+
+ ra->keys[i] = key;
+ ra->containers[i] = c;
+ ra->typecodes[i] = typecode;
+}
+
+// write set bits to an array
+void ra_to_uint32_array(const roaring_array_t *ra, uint32_t *ans);
+
+bool ra_range_uint32_array(const roaring_array_t *ra, size_t offset, size_t limit, uint32_t *ans);
+
+/**
+ * write a bitmap to a buffer. This is meant to be compatible with
+ * the
+ * Java and Go versions. Return the size in bytes of the serialized
+ * output (which should be ra_portable_size_in_bytes(ra)).
+ */
+size_t ra_portable_serialize(const roaring_array_t *ra, char *buf);
+
+/**
+ * read a bitmap from a serialized version. This is meant to be compatible
+ * with the Java and Go versions.
+ * maxbytes indicates how many bytes available from buf.
+ * When the function returns true, roaring_array_t is populated with the data
+ * and *readbytes indicates how many bytes were read. In all cases, if the function
+ * returns true, then maxbytes >= *readbytes.
+ */
+bool ra_portable_deserialize(roaring_array_t *ra, const char *buf, const size_t maxbytes, size_t * readbytes);
+
+/**
+ * Quickly checks whether there is a serialized bitmap at the pointer,
+ * not exceeding size "maxbytes" in bytes. This function does not allocate
+ * memory dynamically.
+ *
+ * This function returns 0 if and only if no valid bitmap is found.
+ * Otherwise, it returns how many bytes are occupied by the bitmap data.
+ */
+size_t ra_portable_deserialize_size(const char *buf, const size_t maxbytes);
+
+/**
+ * How many bytes are required to serialize this bitmap (meant to be
+ * compatible
+ * with Java and Go versions)
+ */
+size_t ra_portable_size_in_bytes(const roaring_array_t *ra);
+
+/**
+ * return true if it contains at least one run container.
+ */
+bool ra_has_run_container(const roaring_array_t *ra);
+
+/**
+ * Size of the header when serializing (meant to be compatible
+ * with Java and Go versions)
+ */
+uint32_t ra_portable_header_size(const roaring_array_t *ra);
+
+/**
+ * If the container at the index i is share, unshare it (creating a local
+ * copy if needed).
+ */
+static inline void ra_unshare_container_at_index(roaring_array_t *ra,
+ uint16_t i) {
+ assert(i < ra->size);
+ ra->containers[i] =
+ get_writable_copy_if_shared(ra->containers[i], &ra->typecodes[i]);
+}
+
+/**
+ * remove at index i, sliding over all entries after i
+ */
+void ra_remove_at_index(roaring_array_t *ra, int32_t i);
+
+
+/**
+* clears all containers, sets the size at 0 and shrinks the memory usage.
+*/
+void ra_reset(roaring_array_t *ra);
+
+/**
+ * remove at index i, sliding over all entries after i. Free removed container.
+ */
+void ra_remove_at_index_and_free(roaring_array_t *ra, int32_t i);
+
+/**
+ * remove a chunk of indices, sliding over entries after it
+ */
+// void ra_remove_index_range(roaring_array_t *ra, int32_t begin, int32_t end);
+
+// used in inplace andNot only, to slide left the containers from
+// the mutated RoaringBitmap that are after the largest container of
+// the argument RoaringBitmap. It is followed by a call to resize.
+//
+void ra_copy_range(roaring_array_t *ra, uint32_t begin, uint32_t end,
+ uint32_t new_begin);
+
+/**
+ * Shifts rightmost $count containers to the left (distance < 0) or
+ * to the right (distance > 0).
+ * Allocates memory if necessary.
+ * This function doesn't free or create new containers.
+ * Caller is responsible for that.
+ */
+void ra_shift_tail(roaring_array_t *ra, int32_t count, int32_t distance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end file include/roaring/roaring_array.h */
+/* begin file include/roaring/roaring.h */
+/*
+An implementation of Roaring Bitmaps in C.
+*/
+
+#ifndef ROARING_H
+#define ROARING_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+typedef struct roaring_bitmap_s {
+ roaring_array_t high_low_container;
+} roaring_bitmap_t;
+
+/**
+ * Creates a new bitmap (initially empty)
+ */
+roaring_bitmap_t *roaring_bitmap_create(void);
+
+/**
+ * Add all the values between min (included) and max (excluded) that are at a
+ * distance k*step from min.
+*/
+roaring_bitmap_t *roaring_bitmap_from_range(uint64_t min, uint64_t max,
+ uint32_t step);
+
+/**
+ * Creates a new bitmap (initially empty) with a provided
+ * container-storage capacity (it is a performance hint).
+ */
+roaring_bitmap_t *roaring_bitmap_create_with_capacity(uint32_t cap);
+
+/**
+ * Creates a new bitmap from a pointer of uint32_t integers
+ */
+roaring_bitmap_t *roaring_bitmap_of_ptr(size_t n_args, const uint32_t *vals);
+
+/*
+ * Whether you want to use copy-on-write.
+ * Saves memory and avoids copies but needs more care in a threaded context.
+ * Most users should ignore this flag.
+ * Note: if you do turn this flag to 'true', enabling COW,
+ * then ensure that you do so for all of your bitmaps since
+ * interactions between bitmaps with and without COW is unsafe.
+ */
+static inline bool roaring_bitmap_get_copy_on_write(const roaring_bitmap_t* r) {
+ return r->high_low_container.flags & ROARING_FLAG_COW;
+}
+static inline void roaring_bitmap_set_copy_on_write(roaring_bitmap_t* r, bool cow) {
+ if (cow) {
+ r->high_low_container.flags |= ROARING_FLAG_COW;
+ } else {
+ r->high_low_container.flags &= ~ROARING_FLAG_COW;
+ }
+}
+
+/**
+ * Describe the inner structure of the bitmap.
+ */
+void roaring_bitmap_printf_describe(const roaring_bitmap_t *ra);
+
+/**
+ * Creates a new bitmap from a list of uint32_t integers
+ */
+roaring_bitmap_t *roaring_bitmap_of(size_t n, ...);
+
+/**
+ * Copies a bitmap. This does memory allocation. The caller is responsible for
+ * memory management.
+ *
+ */
+roaring_bitmap_t *roaring_bitmap_copy(const roaring_bitmap_t *r);
+
+
+/**
+ * Copies a bitmap from src to dest. It is assumed that the pointer dest
+ * is to an already allocated bitmap. The content of the dest bitmap is
+ * freed/deleted.
+ *
+ * It might be preferable and simpler to call roaring_bitmap_copy except
+ * that roaring_bitmap_overwrite can save on memory allocations.
+ *
+ */
+bool roaring_bitmap_overwrite(roaring_bitmap_t *dest,
+ const roaring_bitmap_t *src);
+
+/**
+ * Print the content of the bitmap.
+ */
+void roaring_bitmap_printf(const roaring_bitmap_t *ra);
+
+/**
+ * Computes the intersection between two bitmaps and returns new bitmap. The
+ * caller is
+ * responsible for memory management.
+ *
+ */
+roaring_bitmap_t *roaring_bitmap_and(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Computes the size of the intersection between two bitmaps.
+ *
+ */
+uint64_t roaring_bitmap_and_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+
+/**
+ * Check whether two bitmaps intersect.
+ *
+ */
+bool roaring_bitmap_intersect(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Computes the Jaccard index between two bitmaps. (Also known as the Tanimoto
+ * distance,
+ * or the Jaccard similarity coefficient)
+ *
+ * The Jaccard index is undefined if both bitmaps are empty.
+ *
+ */
+double roaring_bitmap_jaccard_index(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Computes the size of the union between two bitmaps.
+ *
+ */
+uint64_t roaring_bitmap_or_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Computes the size of the difference (andnot) between two bitmaps.
+ *
+ */
+uint64_t roaring_bitmap_andnot_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Computes the size of the symmetric difference (andnot) between two bitmaps.
+ *
+ */
+uint64_t roaring_bitmap_xor_cardinality(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Inplace version modifies x1, x1 == x2 is allowed
+ */
+void roaring_bitmap_and_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Computes the union between two bitmaps and returns new bitmap. The caller is
+ * responsible for memory management.
+ */
+roaring_bitmap_t *roaring_bitmap_or(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Inplace version of roaring_bitmap_or, modifies x1. TDOO: decide whether x1 ==
+ *x2 ok
+ *
+ */
+void roaring_bitmap_or_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Compute the union of 'number' bitmaps. See also roaring_bitmap_or_many_heap.
+ * Caller is responsible for freeing the
+ * result.
+ *
+ */
+roaring_bitmap_t *roaring_bitmap_or_many(size_t number,
+ const roaring_bitmap_t **x);
+
+/**
+ * Compute the union of 'number' bitmaps using a heap. This can
+ * sometimes be faster than roaring_bitmap_or_many which uses
+ * a naive algorithm. Caller is responsible for freeing the
+ * result.
+ *
+ */
+roaring_bitmap_t *roaring_bitmap_or_many_heap(uint32_t number,
+ const roaring_bitmap_t **x);
+
+/**
+ * Computes the symmetric difference (xor) between two bitmaps
+ * and returns new bitmap. The caller is responsible for memory management.
+ */
+roaring_bitmap_t *roaring_bitmap_xor(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Inplace version of roaring_bitmap_xor, modifies x1. x1 != x2.
+ *
+ */
+void roaring_bitmap_xor_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Compute the xor of 'number' bitmaps.
+ * Caller is responsible for freeing the
+ * result.
+ *
+ */
+roaring_bitmap_t *roaring_bitmap_xor_many(size_t number,
+ const roaring_bitmap_t **x);
+
+/**
+ * Computes the difference (andnot) between two bitmaps
+ * and returns new bitmap. The caller is responsible for memory management.
+ */
+roaring_bitmap_t *roaring_bitmap_andnot(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * Inplace version of roaring_bitmap_andnot, modifies x1. x1 != x2.
+ *
+ */
+void roaring_bitmap_andnot_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * TODO: consider implementing:
+ * Compute the xor of 'number' bitmaps using a heap. This can
+ * sometimes be faster than roaring_bitmap_xor_many which uses
+ * a naive algorithm. Caller is responsible for freeing the
+ * result.
+ *
+ * roaring_bitmap_t *roaring_bitmap_xor_many_heap(uint32_t number,
+ * const roaring_bitmap_t **x);
+ */
+
+/**
+ * Frees the memory.
+ */
+void roaring_bitmap_free(const roaring_bitmap_t *r);
+
+/**
+ * Add value n_args from pointer vals, faster than repeatedly calling
+ * roaring_bitmap_add
+ *
+ */
+void roaring_bitmap_add_many(roaring_bitmap_t *r, size_t n_args,
+ const uint32_t *vals);
+
+/**
+ * Add value x
+ *
+ */
+void roaring_bitmap_add(roaring_bitmap_t *r, uint32_t x);
+
+/**
+ * Add value x
+ * Returns true if a new value was added, false if the value was already existing.
+ */
+bool roaring_bitmap_add_checked(roaring_bitmap_t *r, uint32_t x);
+
+/**
+ * Add all values in range [min, max]
+ */
+void roaring_bitmap_add_range_closed(roaring_bitmap_t *ra, uint32_t min, uint32_t max);
+
+/**
+ * Add all values in range [min, max)
+ */
+static inline void roaring_bitmap_add_range(roaring_bitmap_t *ra, uint64_t min, uint64_t max) {
+ if(max == min) return;
+ roaring_bitmap_add_range_closed(ra, (uint32_t)min, (uint32_t)(max - 1));
+}
+
+/**
+ * Remove value x
+ *
+ */
+void roaring_bitmap_remove(roaring_bitmap_t *r, uint32_t x);
+
+/** Remove all values in range [min, max] */
+void roaring_bitmap_remove_range_closed(roaring_bitmap_t *ra, uint32_t min, uint32_t max);
+
+/** Remove all values in range [min, max) */
+static inline void roaring_bitmap_remove_range(roaring_bitmap_t *ra, uint64_t min, uint64_t max) {
+ if(max == min) return;
+ roaring_bitmap_remove_range_closed(ra, (uint32_t)min, (uint32_t)(max - 1));
+}
+
+/** Remove multiple values */
+void roaring_bitmap_remove_many(roaring_bitmap_t *r, size_t n_args,
+ const uint32_t *vals);
+
+/**
+ * Remove value x
+ * Returns true if a new value was removed, false if the value was not existing.
+ */
+bool roaring_bitmap_remove_checked(roaring_bitmap_t *r, uint32_t x);
+
+/**
+ * Check if value x is present
+ */
+static inline bool roaring_bitmap_contains(const roaring_bitmap_t *r, uint32_t val) {
+ const uint16_t hb = val >> 16;
+ /*
+ * the next function call involves a binary search and lots of branching.
+ */
+ int32_t i = ra_get_index(&r->high_low_container, hb);
+ if (i < 0) return false;
+
+ uint8_t typecode;
+ // next call ought to be cheap
+ void *container =
+ ra_get_container_at_index(&r->high_low_container, i, &typecode);
+ // rest might be a tad expensive, possibly involving another round of binary search
+ return container_contains(container, val & 0xFFFF, typecode);
+}
+
+/**
+ * Check whether a range of values from range_start (included) to range_end (excluded) is present
+ */
+bool roaring_bitmap_contains_range(const roaring_bitmap_t *r, uint64_t range_start, uint64_t range_end);
+
+/**
+ * Get the cardinality of the bitmap (number of elements).
+ */
+uint64_t roaring_bitmap_get_cardinality(const roaring_bitmap_t *ra);
+
+/**
+ * Returns the number of elements in the range [range_start, range_end).
+ */
+uint64_t roaring_bitmap_range_cardinality(const roaring_bitmap_t *ra,
+ uint64_t range_start, uint64_t range_end);
+
+/**
+* Returns true if the bitmap is empty (cardinality is zero).
+*/
+bool roaring_bitmap_is_empty(const roaring_bitmap_t *ra);
+
+
+/**
+* Empties the bitmap
+*/
+void roaring_bitmap_clear(roaring_bitmap_t *ra);
+
+/**
+ * Convert the bitmap to an array. Write the output to "ans",
+ * caller is responsible to ensure that there is enough memory
+ * allocated
+ * (e.g., ans = malloc(roaring_bitmap_get_cardinality(mybitmap)
+ * * sizeof(uint32_t))
+ */
+void roaring_bitmap_to_uint32_array(const roaring_bitmap_t *ra, uint32_t *ans);
+
+
+/**
+ * Convert the bitmap to an array from "offset" by "limit". Write the output to "ans".
+ * so, you can get data in paging.
+ * caller is responsible to ensure that there is enough memory
+ * allocated
+ * (e.g., ans = malloc(roaring_bitmap_get_cardinality(limit)
+ * * sizeof(uint32_t))
+ * Return false in case of failure (e.g., insufficient memory)
+ */
+bool roaring_bitmap_range_uint32_array(const roaring_bitmap_t *ra, size_t offset, size_t limit, uint32_t *ans);
+
+/**
+ * Remove run-length encoding even when it is more space efficient
+ * return whether a change was applied
+ */
+bool roaring_bitmap_remove_run_compression(roaring_bitmap_t *r);
+
+/** convert array and bitmap containers to run containers when it is more
+ * efficient;
+ * also convert from run containers when more space efficient. Returns
+ * true if the result has at least one run container.
+ * Additional savings might be possible by calling shrinkToFit().
+ */
+bool roaring_bitmap_run_optimize(roaring_bitmap_t *r);
+
+/**
+ * If needed, reallocate memory to shrink the memory usage. Returns
+ * the number of bytes saved.
+*/
+size_t roaring_bitmap_shrink_to_fit(roaring_bitmap_t *r);
+
+/**
+* write the bitmap to an output pointer, this output buffer should refer to
+* at least roaring_bitmap_size_in_bytes(ra) allocated bytes.
+*
+* see roaring_bitmap_portable_serialize if you want a format that's compatible
+* with Java and Go implementations
+*
+* this format has the benefit of being sometimes more space efficient than
+* roaring_bitmap_portable_serialize
+* e.g., when the data is sparse.
+*
+* Returns how many bytes were written which should be
+* roaring_bitmap_size_in_bytes(ra).
+*/
+size_t roaring_bitmap_serialize(const roaring_bitmap_t *ra, char *buf);
+
+/** use with roaring_bitmap_serialize
+* see roaring_bitmap_portable_deserialize if you want a format that's
+* compatible with Java and Go implementations
+*/
+roaring_bitmap_t *roaring_bitmap_deserialize(const void *buf);
+
+/**
+ * How many bytes are required to serialize this bitmap (NOT compatible
+ * with Java and Go versions)
+ */
+size_t roaring_bitmap_size_in_bytes(const roaring_bitmap_t *ra);
+
+/**
+ * read a bitmap from a serialized version. This is meant to be compatible with
+ * the Java and Go versions. See format specification at
+ * https://github.com/RoaringBitmap/RoaringFormatSpec
+ * In case of failure, a null pointer is returned.
+ * This function is unsafe in the sense that if there is no valid serialized
+ * bitmap at the pointer, then many bytes could be read, possibly causing a buffer
+ * overflow. For a safer approach,
+ * call roaring_bitmap_portable_deserialize_safe.
+ */
+roaring_bitmap_t *roaring_bitmap_portable_deserialize(const char *buf);
+
+/**
+ * read a bitmap from a serialized version in a safe manner (reading up to maxbytes).
+ * This is meant to be compatible with
+ * the Java and Go versions. See format specification at
+ * https://github.com/RoaringBitmap/RoaringFormatSpec
+ * In case of failure, a null pointer is returned.
+ */
+roaring_bitmap_t *roaring_bitmap_portable_deserialize_safe(const char *buf, size_t maxbytes);
+
+/**
+ * Check how many bytes would be read (up to maxbytes) at this pointer if there
+ * is a bitmap, returns zero if there is no valid bitmap.
+ * This is meant to be compatible with
+ * the Java and Go versions. See format specification at
+ * https://github.com/RoaringBitmap/RoaringFormatSpec
+ */
+size_t roaring_bitmap_portable_deserialize_size(const char *buf, size_t maxbytes);
+
+
+/**
+ * How many bytes are required to serialize this bitmap (meant to be compatible
+ * with Java and Go versions). See format specification at
+ * https://github.com/RoaringBitmap/RoaringFormatSpec
+ */
+size_t roaring_bitmap_portable_size_in_bytes(const roaring_bitmap_t *ra);
+
+/**
+ * write a bitmap to a char buffer. The output buffer should refer to at least
+ * roaring_bitmap_portable_size_in_bytes(ra) bytes of allocated memory.
+ * This is meant to be compatible with
+ * the
+ * Java and Go versions. Returns how many bytes were written which should be
+ * roaring_bitmap_portable_size_in_bytes(ra). See format specification at
+ * https://github.com/RoaringBitmap/RoaringFormatSpec
+ */
+size_t roaring_bitmap_portable_serialize(const roaring_bitmap_t *ra, char *buf);
+
+/*
+ * "Frozen" serialization format imitates memory layout of roaring_bitmap_t.
+ * Deserialized bitmap is a constant view of the underlying buffer.
+ * This significantly reduces amount of allocations and copying required during
+ * deserialization.
+ * It can be used with memory mapped files.
+ * Example can be found in benchmarks/frozen_benchmark.c
+ *
+ * [#####] const roaring_bitmap_t *
+ * | | |
+ * +----+ | +-+
+ * | | |
+ * [#####################################] underlying buffer
+ *
+ * Note that because frozen serialization format imitates C memory layout
+ * of roaring_bitmap_t, it is not fixed. It is different on big/little endian
+ * platforms and can be changed in future.
+ */
+
+/**
+ * Returns number of bytes required to serialize bitmap using frozen format.
+ */
+size_t roaring_bitmap_frozen_size_in_bytes(const roaring_bitmap_t *ra);
+
+/**
+ * Serializes bitmap using frozen format.
+ * Buffer size must be at least roaring_bitmap_frozen_size_in_bytes().
+ */
+void roaring_bitmap_frozen_serialize(const roaring_bitmap_t *ra, char *buf);
+
+/**
+ * Creates constant bitmap that is a view of a given buffer.
+ * Buffer must contain data previously written by roaring_bitmap_frozen_serialize(),
+ * and additionally its beginning must be aligned by 32 bytes.
+ * Length must be equal exactly to roaring_bitmap_frozen_size_in_bytes().
+ *
+ * On error, NULL is returned.
+ *
+ * Bitmap returned by this function can be used in all readonly contexts.
+ * Bitmap must be freed as usual, by calling roaring_bitmap_free().
+ * Underlying buffer must not be freed or modified while it backs any bitmaps.
+ */
+const roaring_bitmap_t *roaring_bitmap_frozen_view(const char *buf, size_t length);
+
+
+/**
+ * Iterate over the bitmap elements. The function iterator is called once for
+ * all the values with ptr (can be NULL) as the second parameter of each call.
+ *
+ * roaring_iterator is simply a pointer to a function that returns bool
+ * (true means that the iteration should continue while false means that it
+ * should stop),
+ * and takes (uint32_t,void*) as inputs.
+ *
+ * Returns true if the roaring_iterator returned true throughout (so that
+ * all data points were necessarily visited).
+ */
+bool roaring_iterate(const roaring_bitmap_t *ra, roaring_iterator iterator,
+ void *ptr);
+
+bool roaring_iterate64(const roaring_bitmap_t *ra, roaring_iterator64 iterator,
+ uint64_t high_bits, void *ptr);
+
+/**
+ * Return true if the two bitmaps contain the same elements.
+ */
+bool roaring_bitmap_equals(const roaring_bitmap_t *ra1,
+ const roaring_bitmap_t *ra2);
+
+/**
+ * Return true if all the elements of ra1 are also in ra2.
+ */
+bool roaring_bitmap_is_subset(const roaring_bitmap_t *ra1,
+ const roaring_bitmap_t *ra2);
+
+/**
+ * Return true if all the elements of ra1 are also in ra2 and ra2 is strictly
+ * greater
+ * than ra1.
+ */
+bool roaring_bitmap_is_strict_subset(const roaring_bitmap_t *ra1,
+ const roaring_bitmap_t *ra2);
+
+/**
+ * (For expert users who seek high performance.)
+ *
+ * Computes the union between two bitmaps and returns new bitmap. The caller is
+ * responsible for memory management.
+ *
+ * The lazy version defers some computations such as the maintenance of the
+ * cardinality counts. Thus you need
+ * to call roaring_bitmap_repair_after_lazy after executing "lazy" computations.
+ * It is safe to repeatedly call roaring_bitmap_lazy_or_inplace on the result.
+ * The bitsetconversion conversion is a flag which determines
+ * whether container-container operations force a bitset conversion.
+ **/
+roaring_bitmap_t *roaring_bitmap_lazy_or(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2,
+ const bool bitsetconversion);
+
+/**
+ * (For expert users who seek high performance.)
+ * Inplace version of roaring_bitmap_lazy_or, modifies x1
+ * The bitsetconversion conversion is a flag which determines
+ * whether container-container operations force a bitset conversion.
+ */
+void roaring_bitmap_lazy_or_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2,
+ const bool bitsetconversion);
+
+/**
+ * (For expert users who seek high performance.)
+ *
+ * Execute maintenance operations on a bitmap created from
+ * roaring_bitmap_lazy_or
+ * or modified with roaring_bitmap_lazy_or_inplace.
+ */
+void roaring_bitmap_repair_after_lazy(roaring_bitmap_t *x1);
+
+/**
+ * Computes the symmetric difference between two bitmaps and returns new bitmap.
+ *The caller is
+ * responsible for memory management.
+ *
+ * The lazy version defers some computations such as the maintenance of the
+ * cardinality counts. Thus you need
+ * to call roaring_bitmap_repair_after_lazy after executing "lazy" computations.
+ * It is safe to repeatedly call roaring_bitmap_lazy_xor_inplace on the result.
+ *
+ */
+roaring_bitmap_t *roaring_bitmap_lazy_xor(const roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * (For expert users who seek high performance.)
+ * Inplace version of roaring_bitmap_lazy_xor, modifies x1. x1 != x2
+ *
+ */
+void roaring_bitmap_lazy_xor_inplace(roaring_bitmap_t *x1,
+ const roaring_bitmap_t *x2);
+
+/**
+ * compute the negation of the roaring bitmap within a specified
+ * interval: [range_start, range_end). The number of negated values is
+ * range_end - range_start.
+ * Areas outside the range are passed through unchanged.
+ */
+
+roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *x1,
+ uint64_t range_start, uint64_t range_end);
+
+/**
+ * compute (in place) the negation of the roaring bitmap within a specified
+ * interval: [range_start, range_end). The number of negated values is
+ * range_end - range_start.
+ * Areas outside the range are passed through unchanged.
+ */
+
+void roaring_bitmap_flip_inplace(roaring_bitmap_t *x1, uint64_t range_start,
+ uint64_t range_end);
+
+/**
+ * Selects the element at index 'rank' where the smallest element is at index 0.
+ * If the size of the roaring bitmap is strictly greater than rank, then this
+ function returns true and sets element to the element of given rank.
+ Otherwise, it returns false.
+ */
+bool roaring_bitmap_select(const roaring_bitmap_t *ra, uint32_t rank,
+ uint32_t *element);
+/**
+* roaring_bitmap_rank returns the number of integers that are smaller or equal
+* to x. Thus if x is the first element, this function will return 1. If
+* x is smaller than the smallest element, this function will return 0.
+*
+* The indexing convention differs between roaring_bitmap_select and
+* roaring_bitmap_rank: roaring_bitmap_select refers to the smallest value
+* as having index 0, whereas roaring_bitmap_rank returns 1 when ranking
+* the smallest value.
+*/
+uint64_t roaring_bitmap_rank(const roaring_bitmap_t *bm, uint32_t x);
+
+/**
+* roaring_bitmap_smallest returns the smallest value in the set.
+* Returns UINT32_MAX if the set is empty.
+*/
+uint32_t roaring_bitmap_minimum(const roaring_bitmap_t *bm);
+
+/**
+* roaring_bitmap_smallest returns the greatest value in the set.
+* Returns 0 if the set is empty.
+*/
+uint32_t roaring_bitmap_maximum(const roaring_bitmap_t *bm);
+
+/**
+* (For advanced users.)
+* Collect statistics about the bitmap, see roaring_types.h for
+* a description of roaring_statistics_t
+*/
+void roaring_bitmap_statistics(const roaring_bitmap_t *ra,
+ roaring_statistics_t *stat);
+
+/*********************
+* What follows is code use to iterate through values in a roaring bitmap
+
+roaring_bitmap_t *ra =...
+roaring_uint32_iterator_t i;
+roaring_create_iterator(ra, &i);
+while(i.has_value) {
+ printf("value = %d\n", i.current_value);
+ roaring_advance_uint32_iterator(&i);
+}
+
+Obviously, if you modify the underlying bitmap, the iterator
+becomes invalid. So don't.
+*/
+
+typedef struct roaring_uint32_iterator_s {
+ const roaring_bitmap_t *parent; // owner
+ int32_t container_index; // point to the current container index
+ int32_t in_container_index; // for bitset and array container, this is out
+ // index
+ int32_t run_index; // for run container, this points at the run
+
+ uint32_t current_value;
+ bool has_value;
+
+ const void
+ *container; // should be:
+ // parent->high_low_container.containers[container_index];
+ uint8_t typecode; // should be:
+ // parent->high_low_container.typecodes[container_index];
+ uint32_t highbits; // should be:
+ // parent->high_low_container.keys[container_index]) <<
+ // 16;
+
+} roaring_uint32_iterator_t;
+
+/**
+* Initialize an iterator object that can be used to iterate through the
+* values. If there is a value, then this iterator points to the first value
+* and it->has_value is true. The value is in it->current_value.
+*/
+void roaring_init_iterator(const roaring_bitmap_t *ra,
+ roaring_uint32_iterator_t *newit);
+
+/**
+* Initialize an iterator object that can be used to iterate through the
+* values. If there is a value, then this iterator points to the last value
+* and it->has_value is true. The value is in it->current_value.
+*/
+void roaring_init_iterator_last(const roaring_bitmap_t *ra,
+ roaring_uint32_iterator_t *newit);
+
+/**
+* Create an iterator object that can be used to iterate through the
+* values. Caller is responsible for calling roaring_free_iterator.
+* The iterator is initialized. If there is a value, then this iterator
+* points to the first value and it->has_value is true.
+* The value is in it->current_value.
+*
+* This function calls roaring_init_iterator.
+*/
+roaring_uint32_iterator_t *roaring_create_iterator(const roaring_bitmap_t *ra);
+
+/**
+* Advance the iterator. If there is a new value, then it->has_value is true.
+* The new value is in it->current_value. Values are traversed in increasing
+* orders. For convenience, returns it->has_value.
+*/
+bool roaring_advance_uint32_iterator(roaring_uint32_iterator_t *it);
+
+/**
+* Decrement the iterator. If there is a new value, then it->has_value is true.
+* The new value is in it->current_value. Values are traversed in decreasing
+* orders. For convenience, returns it->has_value.
+*/
+bool roaring_previous_uint32_iterator(roaring_uint32_iterator_t *it);
+
+/**
+* Move the iterator to the first value >= val. If there is a such a value, then it->has_value is true.
+* The new value is in it->current_value. For convenience, returns it->has_value.
+*/
+bool roaring_move_uint32_iterator_equalorlarger(roaring_uint32_iterator_t *it, uint32_t val) ;
+/**
+* Creates a copy of an iterator.
+* Caller must free it.
+*/
+roaring_uint32_iterator_t *roaring_copy_uint32_iterator(
+ const roaring_uint32_iterator_t *it);
+
+/**
+* Free memory following roaring_create_iterator
+*/
+void roaring_free_uint32_iterator(roaring_uint32_iterator_t *it);
+
+/*
+ * Reads next ${count} values from iterator into user-supplied ${buf}.
+ * Returns the number of read elements.
+ * This number can be smaller than ${count}, which means that iterator is drained.
+ *
+ * This function satisfies semantics of iteration and can be used together with
+ * other iterator functions.
+ * - first value is copied from ${it}->current_value
+ * - after function returns, iterator is positioned at the next element
+ */
+uint32_t roaring_read_uint32_iterator(roaring_uint32_iterator_t *it, uint32_t* buf, uint32_t count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end file include/roaring/roaring.h */
diff --git a/src/libsysprof/demangle.cpp b/contrib/elfparser/demangle.cpp
similarity index 100%
rename from src/libsysprof/demangle.cpp
rename to contrib/elfparser/demangle.cpp
diff --git a/src/libsysprof/demangle.h b/contrib/elfparser/demangle.h
similarity index 100%
rename from src/libsysprof/demangle.h
rename to contrib/elfparser/demangle.h
diff --git a/src/libsysprof/elfparser.c b/contrib/elfparser/elfparser.c
similarity index 97%
rename from src/libsysprof/elfparser.c
rename to contrib/elfparser/elfparser.c
index 8816a716..2c6b638b 100644
--- a/src/libsysprof/elfparser.c
+++ b/contrib/elfparser/elfparser.c
@@ -297,6 +297,37 @@ open_mapped_file (const char *filename,
return file;
}
+ElfParser *
+elf_parser_new_from_mmap (GMappedFile *file,
+ GError **error)
+{
+ const guchar *data;
+ gsize length;
+ ElfParser *parser;
+
+ if (file == NULL)
+ return NULL;
+
+ data = (guchar *)g_mapped_file_get_contents (file);
+ length = g_mapped_file_get_length (file);
+ parser = elf_parser_new_from_data (data, length);
+
+ if (!parser)
+ {
+ g_set_error (error,
+ G_FILE_ERROR,
+ G_FILE_ERROR_FAILED,
+ "Failed to load ELF from mmap region");
+ g_mapped_file_unref (file);
+ return NULL;
+ }
+
+ parser->filename = NULL;
+ parser->file = file;
+
+ return parser;
+}
+
ElfParser *
elf_parser_new (const char *filename,
GError **error)
diff --git a/src/libsysprof/elfparser.h b/contrib/elfparser/elfparser.h
similarity index 95%
rename from src/libsysprof/elfparser.h
rename to contrib/elfparser/elfparser.h
index 94fa5c02..fd19e78d 100644
--- a/src/libsysprof/elfparser.h
+++ b/contrib/elfparser/elfparser.h
@@ -27,6 +27,8 @@ typedef struct ElfParser ElfParser;
ElfParser *elf_parser_new_from_data (const guchar *data,
gsize length);
+ElfParser *elf_parser_new_from_mmap (GMappedFile *mapped_file,
+ GError **err);
ElfParser *elf_parser_new (const char *filename,
GError **err);
void elf_parser_free (ElfParser *parser);
diff --git a/contrib/elfparser/meson.build b/contrib/elfparser/meson.build
new file mode 100644
index 00000000..b3c75e6b
--- /dev/null
+++ b/contrib/elfparser/meson.build
@@ -0,0 +1,19 @@
+libelfparser_sources = [
+ 'demangle.cpp',
+ 'elfparser.c',
+]
+
+libelfparser_deps = [
+ dependency('glib-2.0', version: glib_req_version),
+]
+
+libelfparser_static = static_library('elfparser', libelfparser_sources,
+ dependencies: libelfparser_deps,
+ gnu_symbol_visibility: 'hidden',
+)
+
+libelfparser_static_dep = declare_dependency(
+ include_directories: include_directories('.'),
+ dependencies: libelfparser_deps,
+ link_with: libelfparser_static,
+)
diff --git a/contrib/linereader/line-reader-private.h b/contrib/linereader/line-reader-private.h
new file mode 100644
index 00000000..deea4396
--- /dev/null
+++ b/contrib/linereader/line-reader-private.h
@@ -0,0 +1,94 @@
+/* line-reader-private.h
+ *
+ * Copyright 2015-2023 Christian Hergert
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+typedef struct _LineReader
+{
+ char *contents;
+ gsize length;
+ gssize pos;
+} LineReader;
+
+static inline void
+line_reader_init (LineReader *reader,
+ char *contents,
+ gssize length)
+{
+ g_assert (reader != NULL);
+
+ if (length < 0)
+ length = strlen (contents);
+
+ if (contents != NULL)
+ {
+ reader->contents = contents;
+ reader->length = length;
+ reader->pos = 0;
+ }
+ else
+ {
+ reader->contents = NULL;
+ reader->length = 0;
+ reader->pos = 0;
+ }
+}
+
+static inline char *
+line_reader_next (LineReader *reader,
+ gsize *length)
+{
+ char *ret = NULL;
+
+ g_assert (reader != NULL);
+ g_assert (length != NULL);
+
+ if ((reader->contents == NULL) || (reader->pos >= reader->length))
+ {
+ *length = 0;
+ return NULL;
+ }
+
+ ret = &reader->contents [reader->pos];
+
+ for (; reader->pos < reader->length; reader->pos++)
+ {
+ if (reader->contents [reader->pos] == '\n')
+ {
+ *length = &reader->contents [reader->pos] - ret;
+ /* Ingore the \r in \r\n if provided */
+ if (*length > 0 && reader->pos > 0 && reader->contents [reader->pos - 1] == '\r')
+ (*length)--;
+ reader->pos++;
+ return ret;
+ }
+ }
+
+ *length = &reader->contents [reader->pos] - ret;
+
+ return ret;
+}
+
+G_END_DECLS
diff --git a/contrib/linereader/meson.build b/contrib/linereader/meson.build
new file mode 100644
index 00000000..9055b71e
--- /dev/null
+++ b/contrib/linereader/meson.build
@@ -0,0 +1,7 @@
+liblinereader_deps = [
+ dependency('gio-2.0', version: glib_req_version),
+]
+
+liblinereader_static_dep = declare_dependency(
+ include_directories: include_directories('.'),
+)
diff --git a/contrib/meson.build b/contrib/meson.build
new file mode 100644
index 00000000..574a013a
--- /dev/null
+++ b/contrib/meson.build
@@ -0,0 +1,3 @@
+subdir('eggbitset')
+subdir('elfparser')
+subdir('linereader')
diff --git a/meson.build b/meson.build
index 7a8edf33..f41bc27c 100644
--- a/meson.build
+++ b/meson.build
@@ -1,9 +1,9 @@
-project('sysprof', 'c',
+project('sysprof', ['c', 'cpp'],
license: ['GPL3+', 'GPL2+'],
version: '45.alpha',
meson_version: '>=0.59.0',
- default_options: [ 'c_std=gnu11',
- 'cpp_std=c++11',
+ default_options: [ 'c_std=gnu17',
+ 'cpp_std=gnu++17',
'warning_level=2',
]
)
@@ -20,28 +20,48 @@ else
app_id = 'org.gnome.Sysprof'
endif
-libsysprof_api_version = 4
-libsysprof_ui_api_version = 5
+# All libraries share an ABI revision as they are expected
+# to be updated as a set. However, we keep libsysprof-capture
+# at an older version since it's used as a static library
+# from various platform tooling
+soname_major_version = 6
+libsysprof_capture_api_version = 4
+libsysprof_api_version = soname_major_version
version_split = meson.project_version().split('.')
datadir = get_option('datadir')
datadir_for_pc_file = join_paths('${prefix}', datadir)
podir = join_paths(meson.current_source_dir(), 'po')
-glib_req = '2.73.0'
-gtk_req = '4.6'
+# Predetermine some features based on meson_options.txt
+need_gtk = get_option('gtk')
+need_glib = (need_gtk or
+ get_option('examples') or
+ get_option('sysprofd') != 'none' or
+ get_option('tools') or
+ get_option('tests'))
+need_libsysprof = (need_gtk or
+ get_option('libsysprof') or
+ get_option('examples') or
+ get_option('tools') or
+ get_option('tests'))
+
+dex_req = '0.3'
+glib_req = '2.76.0'
+gtk_req = '4.10'
polkit_req = '0.105'
+dex_req_version = '>= @0@'.format(dex_req)
glib_req_version = '>= @0@'.format(glib_req)
gtk_req_version = '>= @0@'.format(gtk_req)
polkit_req_version = '>= @0@'.format(polkit_req)
cc = meson.get_compiler('c')
+cxx = meson.get_compiler('cpp')
-if get_option('libsysprof') or get_option('agent')
- add_languages('cpp', native: false)
- cxx = meson.get_compiler('cpp')
-endif
+glib_dep = dependency('glib-2.0', version: glib_req_version, required: need_glib)
+gtk_dep = dependency('gtk4', version: gtk_req_version, required: need_gtk)
+libsystemd_dep = dependency('libsystemd', required: false)
config_h = configuration_data()
config_h.set_quoted('SYMBOLIC_VERSION', symbolic_version)
@@ -72,25 +92,19 @@ if get_option('default_library') != 'static'
endif
endif
-debugdir = get_option('debugdir')
-if debugdir == ''
- debugdir = join_paths(get_option('prefix'), get_option('libdir'), 'debug')
-endif
-config_h.set_quoted('DEBUGDIR', debugdir)
-
-config_h.set_quoted('GETTEXT_PACKAGE', 'sysprof')
-config_h.set10('ENABLE_NLS', true)
-config_h.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
-config_h.set('LOCALEDIR', 'PACKAGE_LOCALE_DIR')
config_h.set('HAVE_EXECINFO_H', cc.has_header('execinfo.h'))
-
-config_h.set('HAVE_STRLCPY', cc.has_function('strlcpy'))
config_h.set('HAVE_REALLOCARRAY', cc.has_function('reallocarray'))
+config_h.set('HAVE_STRLCPY', cc.has_function('strlcpy'))
+config_h.set('LOCALEDIR', 'PACKAGE_LOCALE_DIR')
+config_h.set10('ENABLE_NLS', true)
+config_h.set_quoted('GETTEXT_PACKAGE', 'sysprof')
+config_h.set_quoted('PACKAGE_LOCALE_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale'))
+config_h.set10('HAVE_LIBSYSTEMD', libsystemd_dep.found())
polkit_agent_dep = dependency('polkit-agent-1', required: false)
-polkit_dep = dependency('polkit-gobject-1', version: polkit_req_version, required: false)
-
config_h.set10('HAVE_POLKIT_AGENT', polkit_agent_dep.found())
+
+polkit_dep = dependency('polkit-gobject-1', version: polkit_req_version, required: false)
config_h.set10('HAVE_POLKIT', polkit_dep.found())
if get_option('libunwind')
@@ -98,7 +112,11 @@ if get_option('libunwind')
# and backtrace() showing up in builds
libunwind_dep = dependency('libunwind-generic', required: true)
config_h.set('ENABLE_LIBUNWIND', libunwind_dep.found())
- config_h.set('HAVE_UNW_SET_CACHE_SIZE', libunwind_dep.found() and cc.has_header_symbol('libunwind.h', 'unw_set_cache_size', dependencies: [libunwind_dep]))
+ config_h.set('HAVE_UNW_SET_CACHE_SIZE',
+ (libunwind_dep.found() and
+ cc.has_header_symbol('libunwind.h',
+ 'unw_set_cache_size',
+ dependencies: [libunwind_dep])))
endif
# Development build setup
@@ -106,36 +124,49 @@ if get_option('development')
config_h.set10('DEVELOPMENT_BUILD', true)
endif
-has_use_clockid = cc.has_member('struct perf_event_attr', 'use_clockid', prefix: '#include ')
-has_clockid = cc.has_member('struct perf_event_attr', 'clockid', prefix: '#include ')
+has_use_clockid = cc.has_member('struct perf_event_attr',
+ 'use_clockid',
+ prefix: '#include ')
+has_clockid = cc.has_member('struct perf_event_attr',
+ 'clockid', prefix:
+ '#include ')
config_h.set('HAVE_PERF_CLOCKID', has_use_clockid and has_clockid)
-add_project_arguments([
- '-I' + meson.current_build_dir(), # config.h
-], language: 'c')
-
-glib_major = glib_req.split('.')[0].to_int()
-glib_minor = glib_req.split('.')[1].to_int()
-gtk_major = gtk_req.split('.')[0].to_int()
-gtk_minor = gtk_req.split('.')[1].to_int()
-
-if glib_minor % 2 == 1
- glib_minor = glib_minor + 1
-endif
-if gtk_minor % 2 == 1
- gtk_minor = gtk_minor + 1
-endif
-
+# For config.h
+add_project_arguments(['-I'+meson.current_build_dir()], language: 'c')
global_c_args = [
+ '-DSYSPROF_COMPILATION',
'-D_GNU_SOURCE',
'-D_POSIX_C_SOURCE=200809L',
- '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
- '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
- '-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
- '-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
]
+# Enforce GLib symbol access by required version
+if need_glib
+ glib_major = glib_req.split('.')[0].to_int()
+ glib_minor = glib_req.split('.')[1].to_int()
+ if glib_minor % 2 == 1
+ glib_minor = glib_minor + 1
+ endif
+ global_c_args += [
+ '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
+ '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_@0@_@1@'.format(glib_major, glib_minor),
+ ]
+endif
+
+# Enforce GTK symbol access by required version
+if need_gtk
+ gtk_major = gtk_req.split('.')[0].to_int()
+ gtk_minor = gtk_req.split('.')[1].to_int()
+ if gtk_minor % 2 == 1
+ gtk_minor = gtk_minor + 1
+ endif
+ global_c_args += [
+ '-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
+ '-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_@0@_@1@'.format(gtk_major, gtk_minor),
+ ]
+endif
+
if host_machine.system() == 'darwin'
global_c_args += ['-D_DARWIN_C_SOURCE']
endif
@@ -155,7 +186,7 @@ test_c_args = [
'-Wswitch-default',
'-Wswitch-enum',
'-Wuninitialized',
- ['-Werror=format-security', '-Werror=format=2' ],
+ ['-Werror=format-security', '-Werror=format=2'],
'-Werror=empty-body',
'-Werror=implicit-function-declaration',
'-Werror=pointer-arith',
@@ -171,13 +202,6 @@ test_c_args = [
'-Werror=undef',
]
-# Until GLib is fixed with regards to volatile type registration
-if cc.get_id() == 'clang'
- test_c_args += ['-Wno-incompatible-pointer-types']
-else
- test_c_args += ['-Werror=incompatible-pointer-types']
-endif
-
foreach arg: test_c_args
if cc.has_multi_arguments(arg)
global_c_args += arg
@@ -229,8 +253,9 @@ int main(void) {
config_h.set10('HAVE_STDATOMIC_H', true)
endif
-needs_service_access = get_option('libsysprof') or get_option('agent')
-install_service_files = needs_service_access or get_option('sysprofd') == 'bundled'
+if need_glib
+ subdir('contrib')
+endif
subdir('src')
subdir('data')
diff --git a/meson_options.txt b/meson_options.txt
index 100ec6b8..d36570ad 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -8,9 +8,6 @@ option('development', type: 'boolean', value: 'false')
# server scenarios.
option('gtk', type: 'boolean')
-# Disable libsysprof/ui (in situations you only want sysprof-capture)
-option('libsysprof', type: 'boolean')
-
# Allow disabling the installation of libsysprof-capture*.a
option('install-static', type: 'boolean')
@@ -29,18 +26,15 @@ option('systemdunitdir', type: 'string',
description: 'Directory for systemd service files'
)
-# An optional location to specify where to locate debug information. This
-# is useful for distributions to set based on their debuginfo setup.
-option('debugdir', type: 'string',
- description: 'Look for global separate debug info in this path'
-)
-
# If Yelp documentation should be installed
option('help', type: 'boolean')
# Disable use of libunwind
option('libunwind', type: 'boolean')
+# Build libsysprof (required by tools, tests, sysprof, etc)
+option('libsysprof', type: 'boolean')
+
# Optionally disable the tools (this is mostly only useful for building only
# libsysprof-capture as a subproject)
option('tools', type: 'boolean')
@@ -52,7 +46,3 @@ option('tests', type: 'boolean')
# Optionally disable the examples (this is mostly only useful for building only
# libsysprof-capture as a subproject)
option('examples', type: 'boolean')
-
-# Optionally build the sysprof-agent tool to allow profiling inside of
-# containers from external system
-option('agent', type: 'boolean', description: 'Build the sysprof-agent utility')
diff --git a/org.gnome.Sysprof.Devel.json b/org.gnome.Sysprof.Devel.json
index cf24683f..1b172493 100644
--- a/org.gnome.Sysprof.Devel.json
+++ b/org.gnome.Sysprof.Devel.json
@@ -98,6 +98,25 @@
}
]
},
+ {
+ "name" : "libdex",
+ "buildsystem" : "meson",
+ "config-opts" : [
+ "--buildtype=debugoptimized",
+ "-Ddocs=false",
+ "-Dintrospection=enabled",
+ "-Dexamples=false",
+ "-Dtests=false",
+ "-Dsysprof=false"
+ ],
+ "sources" : [
+ {
+ "type" : "git",
+ "url" : "https://gitlab.gnome.org/chergert/libdex.git",
+ "branch" : "main"
+ }
+ ]
+ },
{
"name" : "sysprof",
"config-opts" : [
diff --git a/src/libsysprof-capture/mapped-ring-buffer.c b/src/libsysprof-capture/mapped-ring-buffer.c
index c7f2ce2c..ef55c1c1 100644
--- a/src/libsysprof-capture/mapped-ring-buffer.c
+++ b/src/libsysprof-capture/mapped-ring-buffer.c
@@ -335,6 +335,8 @@ mapped_ring_buffer_finalize (MappedRingBuffer *self)
close (self->fd);
self->fd = -1;
}
+
+ free (self);
}
void
diff --git a/src/libsysprof-capture/meson.build b/src/libsysprof-capture/meson.build
index f548f827..aa75b636 100644
--- a/src/libsysprof-capture/meson.build
+++ b/src/libsysprof-capture/meson.build
@@ -19,8 +19,11 @@ if not meson.is_subproject()
install_headers(libsysprof_capture_headers, subdir: sysprof_header_subdir)
endif
-libsysprof_capture_sources = files([
+mapped_ring_buffer_sources = files([
'mapped-ring-buffer.c',
+])
+
+libsysprof_capture_sources = files([
'sysprof-address.c',
'sysprof-capture-condition.c',
'sysprof-capture-cursor.c',
@@ -46,8 +49,9 @@ libsysprof_capture_deps = [
]
libsysprof_capture = static_library(
- 'sysprof-capture-@0@'.format(libsysprof_api_version),
- libsysprof_capture_sources,
+ 'sysprof-capture-@0@'.format(libsysprof_capture_api_version),
+ (libsysprof_capture_sources +
+ mapped_ring_buffer_sources),
dependencies: libsysprof_capture_deps,
c_args: [ '-DSYSPROF_CAPTURE_COMPILATION' ],
@@ -64,7 +68,7 @@ libsysprof_capture_dep = declare_dependency(
dependencies: libsysprof_capture_deps,
include_directories: libsysprof_capture_include_dirs,
)
-meson.override_dependency('sysprof-capture-@0@'.format(libsysprof_api_version), libsysprof_capture_dep)
+meson.override_dependency('sysprof-capture-@0@'.format(libsysprof_capture_api_version), libsysprof_capture_dep)
if install_static
pkgconfig.generate(
@@ -76,3 +80,7 @@ if install_static
libraries_private: libsysprof_capture_deps,
)
endif
+
+if get_option('tests')
+ subdir('tests')
+endif
diff --git a/src/libsysprof-capture/sysprof-capture-cursor.c b/src/libsysprof-capture/sysprof-capture-cursor.c
index 7697ad48..376e8603 100644
--- a/src/libsysprof-capture/sysprof-capture-cursor.c
+++ b/src/libsysprof-capture/sysprof-capture-cursor.c
@@ -175,6 +175,10 @@ sysprof_capture_cursor_foreach (SysprofCaptureCursor *self,
delegate = READ_DELEGATE (sysprof_capture_reader_read_sample);
break;
+ case SYSPROF_CAPTURE_FRAME_TRACE:
+ delegate = READ_DELEGATE (sysprof_capture_reader_read_trace);
+ break;
+
case SYSPROF_CAPTURE_FRAME_LOG:
delegate = READ_DELEGATE (sysprof_capture_reader_read_log);
break;
diff --git a/src/libsysprof-capture/sysprof-capture-reader.c b/src/libsysprof-capture/sysprof-capture-reader.c
index 8f5e02e9..6227af9b 100644
--- a/src/libsysprof-capture/sysprof-capture-reader.c
+++ b/src/libsysprof-capture/sysprof-capture-reader.c
@@ -925,6 +925,52 @@ sysprof_capture_reader_read_sample (SysprofCaptureReader *self)
return sample;
}
+const SysprofCaptureTrace *
+sysprof_capture_reader_read_trace (SysprofCaptureReader *self)
+{
+ SysprofCaptureTrace *trace;
+
+ assert (self != NULL);
+ assert ((self->pos % SYSPROF_CAPTURE_ALIGN) == 0);
+ assert (self->pos <= self->bufsz);
+
+ if (!sysprof_capture_reader_ensure_space_for (self, sizeof *trace))
+ return NULL;
+
+ trace = (SysprofCaptureTrace *)(void *)&self->buf[self->pos];
+
+ sysprof_capture_reader_bswap_frame (self, &trace->frame);
+
+ if (trace->frame.type != SYSPROF_CAPTURE_FRAME_TRACE)
+ return NULL;
+
+ if (trace->frame.len < sizeof *trace)
+ return NULL;
+
+ if (self->endian != __BYTE_ORDER)
+ trace->n_addrs = bswap_16 (trace->n_addrs);
+
+ if (trace->frame.len < (sizeof *trace + (sizeof(SysprofCaptureAddress) * trace->n_addrs)))
+ return NULL;
+
+ if (!sysprof_capture_reader_ensure_space_for (self, trace->frame.len))
+ return NULL;
+
+ trace = (SysprofCaptureTrace *)(void *)&self->buf[self->pos];
+
+ if (SYSPROF_UNLIKELY (self->endian != __BYTE_ORDER))
+ {
+ unsigned int i;
+
+ for (i = 0; i < trace->n_addrs; i++)
+ trace->addrs[i] = bswap_64 (trace->addrs[i]);
+ }
+
+ self->pos += trace->frame.len;
+
+ return trace;
+}
+
const SysprofCaptureCounterDefine *
sysprof_capture_reader_read_counter_define (SysprofCaptureReader *self)
{
@@ -1343,7 +1389,7 @@ array_append (const char ***files,
*files = new_files;
}
- (*files)[*n_files] = new_element ? strdup (new_element) : NULL;
+ (*files)[*n_files] = new_element ? sysprof_strdup (new_element) : NULL;
*n_files = *n_files + 1;
assert (*n_files <= *n_files_allocated);
@@ -1362,7 +1408,10 @@ array_deduplicate (const char **files,
for (last_written = 0, next_to_read = 1; last_written <= next_to_read && next_to_read < *n_files;)
{
if (strcmp (files[next_to_read], files[last_written]) == 0)
- next_to_read++;
+ {
+ free ((char *)files[next_to_read]);
+ next_to_read++;
+ }
else
files[++last_written] = files[next_to_read++];
}
diff --git a/src/libsysprof-capture/sysprof-capture-reader.h b/src/libsysprof-capture/sysprof-capture-reader.h
index 9d10d700..fbf6f143 100644
--- a/src/libsysprof-capture/sysprof-capture-reader.h
+++ b/src/libsysprof-capture/sysprof-capture-reader.h
@@ -111,6 +111,8 @@ const SysprofCaptureProcess *sysprof_capture_reader_read_process (
SYSPROF_AVAILABLE_IN_ALL
const SysprofCaptureSample *sysprof_capture_reader_read_sample (SysprofCaptureReader *self);
SYSPROF_AVAILABLE_IN_ALL
+const SysprofCaptureTrace *sysprof_capture_reader_read_trace (SysprofCaptureReader *self);
+SYSPROF_AVAILABLE_IN_ALL
const SysprofCaptureJitmap *sysprof_capture_reader_read_jitmap (SysprofCaptureReader *self);
SYSPROF_AVAILABLE_IN_ALL
const SysprofCaptureCounterDefine *sysprof_capture_reader_read_counter_define (SysprofCaptureReader *self);
diff --git a/src/libsysprof-capture/sysprof-capture-types.h b/src/libsysprof-capture/sysprof-capture-types.h
index 20295a2e..9be4a0eb 100644
--- a/src/libsysprof-capture/sysprof-capture-types.h
+++ b/src/libsysprof-capture/sysprof-capture-types.h
@@ -140,10 +140,11 @@ typedef enum
SYSPROF_CAPTURE_FRAME_FILE_CHUNK = 13,
SYSPROF_CAPTURE_FRAME_ALLOCATION = 14,
SYSPROF_CAPTURE_FRAME_OVERLAY = 15,
+ SYSPROF_CAPTURE_FRAME_TRACE = 16,
} SysprofCaptureFrameType;
/* Not part of ABI */
-#define SYSPROF_CAPTURE_FRAME_LAST 16
+#define SYSPROF_CAPTURE_FRAME_LAST 17
SYSPROF_ALIGNED_BEGIN(1)
typedef struct
@@ -225,6 +226,18 @@ typedef struct
} SysprofCaptureSample
SYSPROF_ALIGNED_END(1);
+SYSPROF_ALIGNED_BEGIN(1)
+typedef struct
+{
+ SysprofCaptureFrame frame;
+ uint32_t n_addrs : 16;
+ uint32_t entering : 1;
+ uint32_t padding1 : 15;
+ int32_t tid;
+ SysprofCaptureAddress addrs[0];
+} SysprofCaptureTrace
+SYSPROF_ALIGNED_END(1);
+
SYSPROF_ALIGNED_BEGIN(1)
typedef struct
{
@@ -357,6 +370,7 @@ SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureMap) == 56, "SysprofCaptureMap chan
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureJitmap) == 28, "SysprofCaptureJitmap changed size");
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureProcess) == 24, "SysprofCaptureProcess changed size");
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureSample) == 32, "SysprofCaptureSample changed size");
+SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureTrace) == 32, "SysprofCaptureTrace changed size");
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureFork) == 28, "SysprofCaptureFork changed size");
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureExit) == 24, "SysprofCaptureExit changed size");
SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureTimestamp) == 24, "SysprofCaptureTimestamp changed size");
@@ -373,6 +387,7 @@ SYSPROF_STATIC_ASSERT (sizeof (SysprofCaptureOverlay) == 32, "SysprofCaptureOver
SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureAllocation, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureAllocation.addrs is not aligned");
SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureSample, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureSample.addrs is not aligned");
+SYSPROF_STATIC_ASSERT ((offsetof (SysprofCaptureTrace, addrs) % SYSPROF_CAPTURE_ALIGN) == 0, "SysprofCaptureTrace.addrs is not aligned");
static inline int
sysprof_capture_address_compare (SysprofCaptureAddress a,
diff --git a/src/libsysprof-capture/sysprof-capture-writer-cat.c b/src/libsysprof-capture/sysprof-capture-writer-cat.c
index 35de0620..e8de2367 100644
--- a/src/libsysprof-capture/sysprof-capture-writer-cat.c
+++ b/src/libsysprof-capture/sysprof-capture-writer-cat.c
@@ -416,6 +416,32 @@ sysprof_capture_writer_cat (SysprofCaptureWriter *self,
break;
}
+ case SYSPROF_CAPTURE_FRAME_TRACE:
+ {
+ const SysprofCaptureTrace *frame;
+
+ if (!(frame = sysprof_capture_reader_read_trace (reader)))
+ goto panic;
+
+ {
+ SysprofCaptureAddress addrs[frame->n_addrs];
+
+ for (unsigned int z = 0; z < frame->n_addrs; z++)
+ addrs[z] = translate_table_translate (tables, TRANSLATE_ADDR, frame->addrs[z]);
+
+ sysprof_capture_writer_add_trace (self,
+ frame->frame.time,
+ frame->frame.cpu,
+ frame->frame.pid,
+ frame->tid,
+ addrs,
+ frame->n_addrs,
+ frame->entering);
+ }
+
+ break;
+ }
+
case SYSPROF_CAPTURE_FRAME_CTRDEF:
{
const SysprofCaptureCounterDefine *frame;
diff --git a/src/libsysprof-capture/sysprof-capture-writer.c b/src/libsysprof-capture/sysprof-capture-writer.c
index d05981c2..4b703d3d 100644
--- a/src/libsysprof-capture/sysprof-capture-writer.c
+++ b/src/libsysprof-capture/sysprof-capture-writer.c
@@ -798,6 +798,42 @@ sysprof_capture_writer_add_sample (SysprofCaptureWriter *self,
return true;
}
+bool
+sysprof_capture_writer_add_trace (SysprofCaptureWriter *self,
+ int64_t time,
+ int cpu,
+ int32_t pid,
+ int32_t tid,
+ const SysprofCaptureAddress *addrs,
+ unsigned int n_addrs,
+ bool entering)
+{
+ SysprofCaptureTrace *ev;
+ size_t len;
+
+ assert (self != NULL);
+
+ len = sizeof *ev + (n_addrs * sizeof (SysprofCaptureAddress));
+
+ ev = (SysprofCaptureTrace *)sysprof_capture_writer_allocate (self, &len);
+ if (!ev)
+ return false;
+
+ sysprof_capture_writer_frame_init (&ev->frame,
+ len,
+ cpu,
+ pid,
+ time,
+ SYSPROF_CAPTURE_FRAME_SAMPLE);
+ ev->n_addrs = n_addrs;
+ ev->tid = tid;
+ ev->entering = !!entering;
+
+ memcpy (ev->addrs, addrs, (n_addrs * sizeof (SysprofCaptureAddress)));
+
+ return true;
+}
+
bool
sysprof_capture_writer_add_fork (SysprofCaptureWriter *self,
int64_t time,
@@ -1659,7 +1695,7 @@ _sysprof_capture_writer_add_raw (SysprofCaptureWriter *self,
return false;
assert (fr->len == len);
- assert (fr->type < 16);
+ assert (fr->type < SYSPROF_CAPTURE_FRAME_LAST);
memcpy (begin, fr, fr->len);
@@ -1668,3 +1704,14 @@ _sysprof_capture_writer_add_raw (SysprofCaptureWriter *self,
return true;
}
+
+int
+_sysprof_capture_writer_dup_fd (SysprofCaptureWriter *self)
+{
+ assert (self != NULL);
+
+ if (self->fd == -1)
+ return -1;
+
+ return dup (self->fd);
+}
diff --git a/src/libsysprof-capture/sysprof-capture-writer.h b/src/libsysprof-capture/sysprof-capture-writer.h
index 4893c226..bde8c174 100644
--- a/src/libsysprof-capture/sysprof-capture-writer.h
+++ b/src/libsysprof-capture/sysprof-capture-writer.h
@@ -143,6 +143,15 @@ bool sysprof_capture_writer_add_sample (Sy
const SysprofCaptureAddress *addrs,
unsigned int n_addrs);
SYSPROF_AVAILABLE_IN_ALL
+bool sysprof_capture_writer_add_trace (SysprofCaptureWriter *self,
+ int64_t time,
+ int cpu,
+ int32_t pid,
+ int32_t tid,
+ const SysprofCaptureAddress *addrs,
+ unsigned int n_addrs,
+ bool entering);
+SYSPROF_AVAILABLE_IN_ALL
bool sysprof_capture_writer_add_fork (SysprofCaptureWriter *self,
int64_t time,
int cpu,
@@ -235,5 +244,7 @@ SYSPROF_INTERNAL
bool _sysprof_capture_writer_set_time_range (SysprofCaptureWriter *self,
int64_t start_time,
int64_t end_time) SYSPROF_INTERNAL;
+SYSPROF_INTERNAL
+int _sysprof_capture_writer_dup_fd (SysprofCaptureWriter *self);
SYSPROF_END_DECLS
diff --git a/src/libsysprof-capture/sysprof-collector.c b/src/libsysprof-capture/sysprof-collector.c
index 803aa02e..c8fad1b8 100644
--- a/src/libsysprof-capture/sysprof-collector.c
+++ b/src/libsysprof-capture/sysprof-collector.c
@@ -576,6 +576,43 @@ sysprof_collector_sample (SysprofBacktraceFunc backtrace_func,
} COLLECTOR_END;
}
+void
+sysprof_collector_trace (SysprofBacktraceFunc backtrace_func,
+ void *backtrace_data,
+ bool entering)
+{
+ COLLECTOR_BEGIN {
+ SysprofCaptureTrace *ev;
+ size_t len;
+
+ len = sizeof *ev + (sizeof (SysprofCaptureTrace) * MAX_UNWIND_DEPTH);
+
+ if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
+ {
+ int n_addrs;
+
+ /* See comment from sysprof_collector_allocate(). */
+ if (backtrace_func)
+ n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data);
+ else
+ n_addrs = 0;
+
+ ev->n_addrs = ((n_addrs < 0) ? 0 : (n_addrs > MAX_UNWIND_DEPTH) ? MAX_UNWIND_DEPTH : n_addrs);
+ ev->frame.len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs;
+ ev->frame.type = SYSPROF_CAPTURE_FRAME_TRACE;
+ ev->frame.cpu = _do_getcpu ();
+ ev->frame.pid = collector->pid;
+ ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
+ ev->tid = collector->tid;
+ ev->entering = !!entering;
+ ev->padding1 = 0;
+
+ mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
+ }
+
+ } COLLECTOR_END;
+}
+
void
sysprof_collector_mark (int64_t time,
int64_t duration,
diff --git a/src/libsysprof-capture/sysprof-collector.h b/src/libsysprof-capture/sysprof-collector.h
index 6f13a805..c53dc984 100644
--- a/src/libsysprof-capture/sysprof-collector.h
+++ b/src/libsysprof-capture/sysprof-collector.h
@@ -75,6 +75,10 @@ void sysprof_collector_allocate (SysprofCaptureAddress
SYSPROF_AVAILABLE_IN_3_36
void sysprof_collector_sample (SysprofBacktraceFunc backtrace_func,
void *backtrace_data);
+SYSPROF_AVAILABLE_IN_ALL
+void sysprof_collector_trace (SysprofBacktraceFunc backtrace_func,
+ void *backtrace_data,
+ bool entering);
SYSPROF_AVAILABLE_IN_3_36
void sysprof_collector_mark (int64_t time,
int64_t duration,
diff --git a/src/tests/allocs-by-size.c b/src/libsysprof-capture/tests/allocs-by-size.c
similarity index 98%
rename from src/tests/allocs-by-size.c
rename to src/libsysprof-capture/tests/allocs-by-size.c
index d98e0f6f..ade4eb5b 100644
--- a/src/tests/allocs-by-size.c
+++ b/src/libsysprof-capture/tests/allocs-by-size.c
@@ -24,8 +24,8 @@
#include
#include
#include
-#include
-#include
+
+#include
typedef struct
{
diff --git a/src/tests/cross-thread-frees.c b/src/libsysprof-capture/tests/cross-thread-frees.c
similarity index 98%
rename from src/tests/cross-thread-frees.c
rename to src/libsysprof-capture/tests/cross-thread-frees.c
index f931e61c..0a90a34e 100644
--- a/src/tests/cross-thread-frees.c
+++ b/src/libsysprof-capture/tests/cross-thread-frees.c
@@ -23,8 +23,8 @@
#include
#include
#include
-#include
-#include
+
+#include
typedef struct
{
diff --git a/src/tests/find-temp-allocs.c b/src/libsysprof-capture/tests/find-temp-allocs.c
similarity index 100%
rename from src/tests/find-temp-allocs.c
rename to src/libsysprof-capture/tests/find-temp-allocs.c
diff --git a/src/libsysprof-capture/tests/meson.build b/src/libsysprof-capture/tests/meson.build
new file mode 100644
index 00000000..d5d7ddb0
--- /dev/null
+++ b/src/libsysprof-capture/tests/meson.build
@@ -0,0 +1,40 @@
+libsysprof_capture_test_env = [
+ 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
+ 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
+ 'G_DEBUG=gc-friendly',
+ 'GSETTINGS_BACKEND=memory',
+ 'MALLOC_CHECK_=2',
+ 'NO_AT_BRIDGE=1',
+]
+
+libsysprof_capture_testsuite_c_args = [
+ '-DSYSPROF_COMPILATION',
+ '-DG_ENABLE_DEBUG',
+ '-UG_DISABLE_ASSERT',
+ '-UG_DISABLE_CAST_CHECKS',
+]
+
+libsysprof_capture_testsuite = {
+ 'allocs-by-size' : {'skip': true},
+ 'cross-thread-frees' : {'skip': true},
+ 'find-temp-allocs' : {'skip': true},
+ 'rewrite-pid' : {'skip': true},
+ 'test-capture' : {},
+ 'test-capture-cursor' : {},
+ 'test-mapped-ring-buffer' : {},
+}
+
+libsysprof_capture_testsuite_deps = [
+ dependency('gio-2.0'),
+ libsysprof_capture_dep,
+]
+
+foreach test, params: libsysprof_capture_testsuite
+ test_exe = executable(test, '@0@.c'.format(test),
+ c_args: libsysprof_capture_testsuite_c_args,
+ dependencies: libsysprof_capture_testsuite_deps,
+ )
+ if not params.get('skip', false)
+ test(test, test_exe, env: libsysprof_capture_test_env)
+ endif
+endforeach
diff --git a/src/tools/rewrite-pid.c b/src/libsysprof-capture/tests/rewrite-pid.c
similarity index 100%
rename from src/tools/rewrite-pid.c
rename to src/libsysprof-capture/tests/rewrite-pid.c
diff --git a/src/tests/test-capture-cursor.c b/src/libsysprof-capture/tests/test-capture-cursor.c
similarity index 100%
rename from src/tests/test-capture-cursor.c
rename to src/libsysprof-capture/tests/test-capture-cursor.c
diff --git a/src/tests/test-capture.c b/src/libsysprof-capture/tests/test-capture.c
similarity index 99%
rename from src/tests/test-capture.c
rename to src/libsysprof-capture/tests/test-capture.c
index c06ad209..a59dcab4 100644
--- a/src/tests/test-capture.c
+++ b/src/libsysprof-capture/tests/test-capture.c
@@ -732,7 +732,7 @@ test_reader_writer_file (void)
g_autofree gchar *data = NULL;
g_autofree gchar *testfile = NULL;
GByteArray *buf = g_byte_array_new ();
- g_autofree const gchar **files = NULL;
+ const char **files;
SysprofCaptureWriter *writer;
SysprofCaptureReader *reader;
SysprofCaptureFrameType type;
@@ -799,6 +799,7 @@ test_reader_writer_file (void)
g_assert_nonnull (files);
g_assert_cmpstr (files[0], ==, testfile);
g_assert_null (files[1]);
+ free (files);
sysprof_capture_reader_reset (reader);
new_fd = sysprof_memfd_create ("[sysprof-capture-file]");
diff --git a/src/tests/test-mapped-ring-buffer.c b/src/libsysprof-capture/tests/test-mapped-ring-buffer.c
similarity index 97%
rename from src/tests/test-mapped-ring-buffer.c
rename to src/libsysprof-capture/tests/test-mapped-ring-buffer.c
index 707c0dcb..444df156 100644
--- a/src/tests/test-mapped-ring-buffer.c
+++ b/src/libsysprof-capture/tests/test-mapped-ring-buffer.c
@@ -163,6 +163,9 @@ test_threaded_movements (void)
g_thread_join (thread1);
g_thread_join (thread2);
+
+ mapped_ring_buffer_unref (writer);
+ mapped_ring_buffer_unref (reader);
}
static void
@@ -183,6 +186,8 @@ test_readwrite (void)
mapped_ring_buffer_advance (ring, sizeof *ptr);
}
mapped_ring_buffer_drain (ring, drain_count_cb, NULL);
+
+ mapped_ring_buffer_unref (ring);
}
gint
diff --git a/src/libsysprof-ui/css/SysprofDisplay-shared.css b/src/libsysprof-ui/css/SysprofDisplay-shared.css
deleted file mode 100644
index a4ca6d57..00000000
--- a/src/libsysprof-ui/css/SysprofDisplay-shared.css
+++ /dev/null
@@ -1,86 +0,0 @@
-SysprofVisualizer {
- background: @content_view_bg;
- }
-SysprofVisualizer:not(:last-child) {
- border-bottom: 1px solid alpha(@borders, 0.3);
- }
-
-SysprofVisualizerGroup {
- border-bottom: 1px solid @borders;
- }
-SysprofVisualizerGroup:last-child {
- box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
- }
-
-SysprofVisualizersFrame box.horizontal.inline-toolbar {
- padding: 0;
- margin: 0;
- border: none;
- border-radius: 0;
- border-width: 0;
- }
-
-SysprofVisualizersFrame viewport.visualizers {
- border-right: 1px solid @borders;
- box-shadow: 1px 1px 3px alpha(@borders, 0.5);
- }
-
-SysprofVisualizersFrame scrollbar.horizontal {
- color: mix(@theme_fg_color, @theme_selected_bg_color, 0.5);
- background: transparent;
- }
-
-SysprofVisualizersFrame scrollbar.horizontal range trough {
- background: transparent;
- }
-
-SysprofVisualizersFrame scrollbar.horizontal range trough slider {
- margin-left: 1px;
- margin-right: 1px;
- padding: 6px;
- min-height: 14px;
- background: alpha(@content_view_bg, 0.2);
- border-radius: 3px;
- border: 2px solid @theme_selected_bg_color;
- box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
- inset 0 -15px 5px alpha(@content_view_bg,.1),
- 0px 2px 4px @borders;
- }
-
-SysprofVisualizerTicks {
- color: mix(@theme_fg_color, @borders, 0.5);
- background-color: @content_view_bg;
- }
-
-SysprofVisualizersFrame list {
- background-color: @theme_bg_color;
- }
-
-SysprofVisualizersFrame list.visualizer-groups row {
- padding: 0;
- border-bottom: 1px solid @borders;
- }
-SysprofVisualizersFrame list.visualizer-groups row:not(:selected) {
- background-color: @theme_bg_color;
- }
-SysprofVisualizersFrame list.visualizer-groups row:last-child {
- box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
- }
-
-SysprofVisualizersFrame .left-column .small-button.flat {
- border-color: transparent;
- min-height: 8px;
- min-width: 8px;
- }
-SysprofVisualizersFrame .left-column .small-button.flat:checked,
-SysprofVisualizersFrame .left-column .small-button.flat:hover {
- border-color: @borders;
- }
-
-SysprofVisualizersFrame .selection {
- border-radius: 3px;
- background-color: alpha(@theme_selected_bg_color, 0.35);
- box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
- inset 0 -15px 5px alpha(@content_view_bg,.1),
- inset 0 0 1px 1px @theme_selected_bg_color;
- }
diff --git a/src/libsysprof-ui/css/SysprofEnvironEditor-shared.css b/src/libsysprof-ui/css/SysprofEnvironEditor-shared.css
deleted file mode 100644
index e202b29b..00000000
--- a/src/libsysprof-ui/css/SysprofEnvironEditor-shared.css
+++ /dev/null
@@ -1,13 +0,0 @@
-list.environ-editor row button.flat:last-child {
- min-height: 16px;
- min-width: 16px;
- padding: 0;
- margin: 3px;
-}
-list.environ-editor row button.flat:not(:hover) {
- border-color: transparent;
-}
-list.environ-editor row button.flat image {
- padding: 3px;
- margin: 0;
-}
diff --git a/src/libsysprof-ui/css/SysprofProfilerAssistant-shared.css b/src/libsysprof-ui/css/SysprofProfilerAssistant-shared.css
deleted file mode 100644
index f0acc7e4..00000000
--- a/src/libsysprof-ui/css/SysprofProfilerAssistant-shared.css
+++ /dev/null
@@ -1,7 +0,0 @@
-sysprofaidicon image.right.top {
- border-radius: 9999px;
- background-color: @theme_selected_bg_color;
- color: @theme_selected_fg_color;
- padding: 2px;
- margin: 0px;
-}
diff --git a/src/libsysprof-ui/egg-handle-private.h b/src/libsysprof-ui/egg-handle-private.h
deleted file mode 100644
index 9c004aa0..00000000
--- a/src/libsysprof-ui/egg-handle-private.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* egg-handle.h
- *
- * Copyright 2021 Christian Hergert
- *
- * This file 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 3 of the License, or (at your option)
- * any later version.
- *
- * This file 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 General Public License along
- * with this program. If not, see .
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define EGG_TYPE_HANDLE (egg_handle_get_type())
-
-G_DECLARE_FINAL_TYPE (EggHandle, egg_handle, EGG, HANDLE, GtkWidget)
-
-GtkWidget *egg_handle_new (GtkPositionType position);
-void egg_handle_set_position (EggHandle *self,
- GtkPositionType position);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/egg-handle.c b/src/libsysprof-ui/egg-handle.c
deleted file mode 100644
index 5872abb3..00000000
--- a/src/libsysprof-ui/egg-handle.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* egg-handle.c
- *
- * Copyright 2021 Christian Hergert
- *
- * This file 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 3 of the License, or (at your option)
- * any later version.
- *
- * This file 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 General Public License along
- * with this program. If not, see .
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- */
-
-#include "config.h"
-
-#include "egg-handle-private.h"
-
-#define EXTRA_SIZE 8
-
-struct _EggHandle
-{
- GtkWidget parent_instance;
- GtkWidget *separator;
- GtkPositionType position : 3;
-};
-
-G_DEFINE_TYPE (EggHandle, egg_handle, GTK_TYPE_WIDGET)
-
-static gboolean
-egg_handle_contains (GtkWidget *widget,
- double x,
- double y)
-{
- EggHandle *self = (EggHandle *)widget;
- graphene_rect_t area;
-
- g_assert (EGG_IS_HANDLE (self));
-
- if (!gtk_widget_compute_bounds (GTK_WIDGET (self->separator),
- GTK_WIDGET (self),
- &area))
- return FALSE;
-
- switch (self->position)
- {
- case GTK_POS_LEFT:
- area.origin.x -= EXTRA_SIZE;
- area.size.width = EXTRA_SIZE;
- break;
-
- case GTK_POS_RIGHT:
- area.size.width = EXTRA_SIZE;
- break;
-
- case GTK_POS_TOP:
- area.origin.y -= EXTRA_SIZE;
- area.size.height = EXTRA_SIZE;
- break;
-
- case GTK_POS_BOTTOM:
- area.size.height = EXTRA_SIZE;
- break;
-
- default:
- g_assert_not_reached ();
- break;
- }
-
- return graphene_rect_contains_point (&area, &GRAPHENE_POINT_INIT (x, y));
-}
-
-static void
-egg_handle_dispose (GObject *object)
-{
- EggHandle *self = (EggHandle *)object;
-
- g_clear_pointer (&self->separator, gtk_widget_unparent);
-
- G_OBJECT_CLASS (egg_handle_parent_class)->dispose (object);
-}
-
-static void
-egg_handle_class_init (EggHandleClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = egg_handle_dispose;
-
- widget_class->contains = egg_handle_contains;
-
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
-}
-
-static void
-egg_handle_init (EggHandle *self)
-{
- self->separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
- gtk_widget_set_parent (GTK_WIDGET (self->separator), GTK_WIDGET (self));
-}
-
-void
-egg_handle_set_position (EggHandle *self,
- GtkPositionType position)
-{
- g_return_if_fail (EGG_IS_HANDLE (self));
-
- self->position = position;
-
- switch (position)
- {
- case GTK_POS_LEFT:
- case GTK_POS_RIGHT:
- gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "col-resize");
- gtk_orientable_set_orientation (GTK_ORIENTABLE (self->separator), GTK_ORIENTATION_VERTICAL);
- break;
-
- case GTK_POS_TOP:
- case GTK_POS_BOTTOM:
- gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "row-resize");
- gtk_orientable_set_orientation (GTK_ORIENTABLE (self->separator), GTK_ORIENTATION_HORIZONTAL);
- break;
-
- default:
- g_assert_not_reached ();
- }
-}
-
-GtkWidget *
-egg_handle_new (GtkPositionType position)
-{
- EggHandle *self;
-
- self = g_object_new (EGG_TYPE_HANDLE, NULL);
- egg_handle_set_position (self, position);
-
- return GTK_WIDGET (self);
-}
diff --git a/src/libsysprof-ui/egg-paned-private.h b/src/libsysprof-ui/egg-paned-private.h
deleted file mode 100644
index b673c1a4..00000000
--- a/src/libsysprof-ui/egg-paned-private.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* egg-paned.h
- *
- * Copyright 2021 Christian Hergert
- *
- * This file 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 3 of the License, or (at your option)
- * any later version.
- *
- * This file 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 General Public License along
- * with this program. If not, see .
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define EGG_TYPE_PANED (egg_paned_get_type())
-
-G_DECLARE_FINAL_TYPE (EggPaned, egg_paned, EGG, PANED, GtkWidget)
-
-GtkWidget *egg_paned_new (void);
-void egg_paned_append (EggPaned *self,
- GtkWidget *child);
-void egg_paned_prepend (EggPaned *self,
- GtkWidget *child);
-void egg_paned_insert (EggPaned *self,
- int position,
- GtkWidget *child);
-void egg_paned_insert_after (EggPaned *self,
- GtkWidget *child,
- GtkWidget *sibling);
-void egg_paned_remove (EggPaned *self,
- GtkWidget *child);
-guint egg_paned_get_n_children (EggPaned *self);
-GtkWidget *egg_paned_get_nth_child (EggPaned *self,
- guint nth);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/egg-paned.c b/src/libsysprof-ui/egg-paned.c
deleted file mode 100644
index 25b0d82c..00000000
--- a/src/libsysprof-ui/egg-paned.c
+++ /dev/null
@@ -1,593 +0,0 @@
-/* egg-paned.c
- *
- * Copyright 2021 Christian Hergert
- *
- * This file 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 3 of the License, or (at your option)
- * any later version.
- *
- * This file 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 General Public License along
- * with this program. If not, see .
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- */
-
-#include "config.h"
-
-#include
-
-#include "egg-paned-private.h"
-#include "egg-resizer-private.h"
-
-struct _EggPaned
-{
- GtkWidget parent_instance;
- GtkOrientation orientation;
-};
-
-static void buildable_iface_init (GtkBuildableIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (EggPaned, egg_paned, GTK_TYPE_WIDGET,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
-
-enum {
- PROP_0,
- N_PROPS,
-
- PROP_ORIENTATION,
-};
-
-static void
-update_orientation (GtkWidget *widget,
- GtkOrientation orientation)
-{
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- gtk_widget_remove_css_class (widget, "vertical");
- gtk_widget_add_css_class (widget, "horizontal");
- }
- else
- {
- gtk_widget_remove_css_class (widget, "horizontal");
- gtk_widget_add_css_class (widget, "vertical");
- }
-
- gtk_accessible_update_property (GTK_ACCESSIBLE (widget),
- GTK_ACCESSIBLE_PROPERTY_ORIENTATION, orientation,
- -1);
-}
-
-/**
- * egg_paned_new:
- *
- * Create a new #EggPaned.
- *
- * Returns: (transfer full): a newly created #EggPaned
- */
-GtkWidget *
-egg_paned_new (void)
-{
- return g_object_new (EGG_TYPE_PANED, NULL);
-}
-
-static void
-egg_paned_set_orientation (EggPaned *self,
- GtkOrientation orientation)
-{
- GtkPositionType pos;
-
- g_assert (EGG_IS_PANED (self));
- g_assert (orientation == GTK_ORIENTATION_HORIZONTAL ||
- orientation == GTK_ORIENTATION_VERTICAL);
-
- if (self->orientation == orientation)
- return;
-
- self->orientation = orientation;
-
- if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
- pos = GTK_POS_LEFT;
- else
- pos = GTK_POS_TOP;
-
- for (GtkWidget *child = gtk_widget_get_last_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_prev_sibling (child))
- {
- g_assert (EGG_IS_RESIZER (child));
-
- egg_resizer_set_position (EGG_RESIZER (child), pos);
- }
-
- update_orientation (GTK_WIDGET (self), self->orientation);
- gtk_widget_queue_resize (GTK_WIDGET (self));
- g_object_notify (G_OBJECT (self), "orientation");
-}
-
-static void
-egg_paned_measure (GtkWidget *widget,
- GtkOrientation orientation,
- int for_size,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
-{
- EggPaned *self = (EggPaned *)widget;
-
- g_assert (EGG_IS_PANED (self));
-
- *minimum = 0;
- *natural = 0;
- *minimum_baseline = -1;
- *natural_baseline = -1;
-
- for (GtkWidget *child = gtk_widget_get_first_child (widget);
- child != NULL;
- child = gtk_widget_get_next_sibling (child))
- {
- int child_min, child_nat;
-
- gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL);
-
- if (orientation == self->orientation)
- {
- *minimum += child_min;
- *natural += child_nat;
- }
- else
- {
- *minimum = MAX (*minimum, child_min);
- *natural = MAX (*natural, child_nat);
- }
- }
-}
-
-typedef struct
-{
- GtkWidget *widget;
- GtkRequisition min_request;
- GtkRequisition nat_request;
- GtkAllocation alloc;
-} ChildAllocation;
-
-static void
-egg_paned_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline)
-{
- EggPaned *self = (EggPaned *)widget;
- ChildAllocation *allocs;
- ChildAllocation *last_alloc = NULL;
- GtkOrientation orientation;
- guint n_children = 0;
- guint n_expand = 0;
- guint i;
- int extra_width = width;
- int extra_height = height;
- int expand_width;
- int expand_height;
- int x, y;
-
- g_assert (EGG_IS_PANED (self));
-
- GTK_WIDGET_CLASS (egg_paned_parent_class)->size_allocate (widget, width, height, baseline);
-
- n_children = egg_paned_get_n_children (self);
-
- if (n_children == 1)
- {
- GtkWidget *child = gtk_widget_get_first_child (widget);
- GtkAllocation alloc = { 0, 0, width, height };
-
- if (gtk_widget_get_visible (child))
- {
- gtk_widget_size_allocate (child, &alloc, -1);
- return;
- }
- }
-
- orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (self));
- allocs = g_newa (ChildAllocation, n_children);
- memset (allocs, 0, sizeof *allocs * n_children);
-
- /* Give min size to each of the children */
- i = 0;
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_next_sibling (child), i++)
- {
- ChildAllocation *child_alloc = &allocs[i];
-
- if (!gtk_widget_get_visible (child))
- continue;
-
- gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, height,
- &child_alloc->min_request.width,
- &child_alloc->nat_request.width,
- NULL, NULL);
- gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, width,
- &child_alloc->min_request.height,
- &child_alloc->nat_request.height,
- NULL, NULL);
-
- child_alloc->alloc.width = child_alloc->min_request.width;
- child_alloc->alloc.height = child_alloc->min_request.height;
-
- n_expand += gtk_widget_compute_expand (child, orientation);
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- extra_width -= child_alloc->alloc.width;
- child_alloc->alloc.height = height;
- }
- else
- {
- extra_height -= child_alloc->alloc.height;
- child_alloc->alloc.width = width;
- }
- }
-
- /* Now try to distribute extra space for natural size */
- i = 0;
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_next_sibling (child), i++)
- {
- ChildAllocation *child_alloc = &allocs[i];
-
- if (!gtk_widget_get_visible (child))
- continue;
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- int taken = MIN (extra_width, child_alloc->nat_request.width - child_alloc->alloc.width);
-
- if (taken > 0)
- {
- child_alloc->alloc.width += taken;
- extra_width -= taken;
- }
- }
- else
- {
- int taken = MIN (extra_height, child_alloc->nat_request.height - child_alloc->alloc.height);
-
- if (taken > 0)
- {
- child_alloc->alloc.height += taken;
- extra_height -= taken;
- }
- }
-
- last_alloc = child_alloc;
- }
-
- /* Now give extra space for those that expand */
- expand_width = n_expand ? extra_width / n_expand : 0;
- expand_height = n_expand ? extra_height / n_expand : 0;
- i = n_children;
- for (GtkWidget *child = gtk_widget_get_last_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_prev_sibling (child), i--)
- {
- ChildAllocation *child_alloc = &allocs[i-1];
-
- if (!gtk_widget_get_visible (child))
- continue;
-
- if (!gtk_widget_compute_expand (child, orientation))
- continue;
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- child_alloc->alloc.width += expand_width;
- extra_width -= expand_width;
- }
- else
- {
- child_alloc->alloc.height += expand_height;
- extra_height -= expand_height;
- }
- }
-
- /* Give any leftover to the last visible child */
- if (last_alloc)
- {
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- last_alloc->alloc.width += extra_width;
- else
- last_alloc->alloc.height += extra_height;
- }
-
- i = 0;
- x = 0;
- y = 0;
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_next_sibling (child), i++)
- {
- ChildAllocation *child_alloc = &allocs[i];
-
- child_alloc->alloc.x = x;
- child_alloc->alloc.y = y;
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- x += child_alloc->alloc.width;
- else
- y += child_alloc->alloc.height;
-
- gtk_widget_size_allocate (child, &child_alloc->alloc, -1);
- }
-}
-
-static void
-egg_paned_dispose (GObject *object)
-{
- EggPaned *self = (EggPaned *)object;
- GtkWidget *child;
-
- child = gtk_widget_get_first_child (GTK_WIDGET (self));
- while (child)
- {
- GtkWidget *next = gtk_widget_get_next_sibling (child);
- gtk_widget_unparent (child);
- child = next;
- }
-
- G_OBJECT_CLASS (egg_paned_parent_class)->dispose (object);
-}
-
-static void
-egg_paned_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- EggPaned *self = EGG_PANED (object);
-
- switch (prop_id)
- {
- case PROP_ORIENTATION:
- g_value_set_enum (value, self->orientation);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-egg_paned_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- EggPaned *self = EGG_PANED (object);
-
- switch (prop_id)
- {
- case PROP_ORIENTATION:
- egg_paned_set_orientation (self, g_value_get_enum (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-egg_paned_class_init (EggPanedClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = egg_paned_dispose;
- object_class->get_property = egg_paned_get_property;
- object_class->set_property = egg_paned_set_property;
-
- widget_class->measure = egg_paned_measure;
- widget_class->size_allocate = egg_paned_size_allocate;
-
- g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
-
- gtk_widget_class_set_css_name (widget_class, "eggpaned");
-}
-
-static void
-egg_paned_init (EggPaned *self)
-{
- self->orientation = GTK_ORIENTATION_HORIZONTAL;
-
- update_orientation (GTK_WIDGET (self), self->orientation);
-}
-
-static void
-egg_paned_update_handles (EggPaned *self)
-{
- GtkWidget *child;
-
- g_assert (EGG_IS_PANED (self));
-
- for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_next_sibling (child))
- {
- GtkWidget *handle;
-
- g_assert (EGG_IS_RESIZER (child));
-
- if ((handle = egg_resizer_get_handle (EGG_RESIZER (child))))
- gtk_widget_show (handle);
- }
-
- if ((child = gtk_widget_get_last_child (GTK_WIDGET (self))))
- {
- GtkWidget *handle = egg_resizer_get_handle (EGG_RESIZER (child));
- gtk_widget_hide (handle);
- }
-}
-
-void
-egg_paned_remove (EggPaned *self,
- GtkWidget *child)
-{
- GtkWidget *resizer;
-
- g_return_if_fail (EGG_IS_PANED (self));
- g_return_if_fail (GTK_IS_WIDGET (child));
-
- resizer = gtk_widget_get_ancestor (child, EGG_TYPE_RESIZER);
- g_return_if_fail (resizer != NULL &&
- gtk_widget_get_parent (resizer) == GTK_WIDGET (self));
- gtk_widget_unparent (resizer);
- egg_paned_update_handles (self);
- gtk_widget_queue_resize (GTK_WIDGET (self));
-}
-
-void
-egg_paned_insert (EggPaned *self,
- int position,
- GtkWidget *child)
-{
- GtkPositionType pos;
- GtkWidget *resizer;
-
- g_return_if_fail (EGG_IS_PANED (self));
- g_return_if_fail (GTK_IS_WIDGET (child));
- g_return_if_fail (gtk_widget_get_parent (child) == NULL);
-
- if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
- pos = GTK_POS_LEFT;
- else
- pos = GTK_POS_TOP;
-
- resizer = egg_resizer_new (pos);
- egg_resizer_set_child (EGG_RESIZER (resizer), child);
-
- if (position < 0)
- gtk_widget_insert_before (GTK_WIDGET (resizer), GTK_WIDGET (self), NULL);
- else if (position == 0)
- gtk_widget_insert_after (GTK_WIDGET (resizer), GTK_WIDGET (self), NULL);
- else
- {
- GtkWidget *sibling = gtk_widget_get_first_child (GTK_WIDGET (self));
-
- for (int i = position; i > 0 && sibling != NULL; i--)
- sibling = gtk_widget_get_next_sibling (sibling);
-
- gtk_widget_insert_before (GTK_WIDGET (resizer), GTK_WIDGET (self), sibling);
- }
-
- egg_paned_update_handles (self);
-
- gtk_widget_queue_resize (GTK_WIDGET (self));
-}
-
-void
-egg_paned_append (EggPaned *self,
- GtkWidget *child)
-{
- egg_paned_insert (self, -1, child);
-}
-
-void
-egg_paned_prepend (EggPaned *self,
- GtkWidget *child)
-{
- egg_paned_insert (self, 0, child);
-}
-
-void
-egg_paned_insert_after (EggPaned *self,
- GtkWidget *child,
- GtkWidget *sibling)
-{
- int position = 0;
-
- g_return_if_fail (EGG_IS_PANED (self));
- g_return_if_fail (GTK_IS_WIDGET (child));
- g_return_if_fail (!sibling || GTK_IS_WIDGET (sibling));
-
- if (sibling == NULL)
- {
- egg_paned_prepend (self, child);
- return;
- }
-
- /* TODO: We should reverse insert() to call this */
-
- for (GtkWidget *ancestor = gtk_widget_get_first_child (GTK_WIDGET (self));
- ancestor != NULL;
- ancestor = gtk_widget_get_next_sibling (ancestor))
- {
- position++;
-
- if (sibling == ancestor || gtk_widget_is_ancestor (sibling, ancestor))
- break;
- }
-
- egg_paned_insert (self, position, child);
-}
-
-guint
-egg_paned_get_n_children (EggPaned *self)
-{
- guint count = 0;
-
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_next_sibling (child))
- count++;
-
- return count;
-}
-
-GtkWidget *
-egg_paned_get_nth_child (EggPaned *self,
- guint nth)
-{
- g_return_val_if_fail (EGG_IS_PANED (self), NULL);
-
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
- child != NULL;
- child = gtk_widget_get_next_sibling (child))
- {
- g_assert (EGG_IS_RESIZER (child));
-
- if (nth == 0)
- return egg_resizer_get_child (EGG_RESIZER (child));
-
- nth--;
- }
-
- return NULL;
-}
-
-static void
-egg_paned_add_child (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const char *type)
-{
- if (GTK_IS_WIDGET (child))
- egg_paned_append (EGG_PANED (buildable), GTK_WIDGET (child));
- else
- g_warning ("Cannot add child of type %s to %s",
- G_OBJECT_TYPE_NAME (child),
- G_OBJECT_TYPE_NAME (buildable));
-}
-
-static void
-buildable_iface_init (GtkBuildableIface *iface)
-{
- iface->add_child = egg_paned_add_child;
-}
diff --git a/src/libsysprof-ui/egg-resizer-private.h b/src/libsysprof-ui/egg-resizer-private.h
deleted file mode 100644
index 58db56c3..00000000
--- a/src/libsysprof-ui/egg-resizer-private.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* egg-resizer.h
- *
- * Copyright 2021 Christian Hergert
- *
- * This file 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 3 of the License, or (at your option)
- * any later version.
- *
- * This file 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 General Public License along
- * with this program. If not, see .
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define EGG_TYPE_RESIZER (egg_resizer_get_type())
-
-G_DECLARE_FINAL_TYPE (EggResizer, egg_resizer, EGG, RESIZER, GtkWidget)
-
-GtkWidget *egg_resizer_new (GtkPositionType position);
-GtkPositionType egg_resizer_get_position (EggResizer *self);
-void egg_resizer_set_position (EggResizer *self,
- GtkPositionType position);
-GtkWidget *egg_resizer_get_child (EggResizer *self);
-void egg_resizer_set_child (EggResizer *self,
- GtkWidget *child);
-GtkWidget *egg_resizer_get_handle (EggResizer *self);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/egg-resizer.c b/src/libsysprof-ui/egg-resizer.c
deleted file mode 100644
index c2b427bc..00000000
--- a/src/libsysprof-ui/egg-resizer.c
+++ /dev/null
@@ -1,495 +0,0 @@
-/* egg-resizer.c
- *
- * Copyright 2021 Christian Hergert
- *
- * This file 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 3 of the License, or (at your option)
- * any later version.
- *
- * This file 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 General Public License along
- * with this program. If not, see .
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- */
-
-#include "config.h"
-
-#include "egg-handle-private.h"
-#include "egg-resizer-private.h"
-
-#define HANDLE_SIZE 8
-
-struct _EggResizer
-{
- GtkWidget parent_instance;
-
- EggHandle *handle;
- GtkWidget *child;
-
- double drag_orig_size;
- double drag_position;
-
- GtkPositionType position : 3;
-};
-
-G_DEFINE_TYPE (EggResizer, egg_resizer, GTK_TYPE_WIDGET)
-
-enum {
- PROP_0,
- PROP_CHILD,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-static void
-egg_resizer_drag_begin_cb (EggResizer *self,
- double start_x,
- double start_y,
- GtkGestureDrag *drag)
-{
- GtkAllocation child_alloc;
- GtkAllocation handle_alloc;
-
- g_assert (EGG_IS_RESIZER (self));
- g_assert (GTK_IS_GESTURE_DRAG (drag));
-
- if (self->child == NULL)
- return;
-
- switch (self->position)
- {
- case GTK_POS_LEFT:
- if (start_x > gtk_widget_get_width (GTK_WIDGET (self)) - HANDLE_SIZE)
- goto start_drag;
- break;
-
- case GTK_POS_RIGHT:
- if (start_x <= HANDLE_SIZE)
- goto start_drag;
- break;
-
- case GTK_POS_TOP:
- if (start_y > gtk_widget_get_height (GTK_WIDGET (self)) - HANDLE_SIZE)
- goto start_drag;
- break;
-
- case GTK_POS_BOTTOM:
- if (start_y <= HANDLE_SIZE)
- goto start_drag;
- break;
-
- default:
- g_assert_not_reached ();
- break;
- }
-
- gtk_gesture_set_state (GTK_GESTURE (drag),
- GTK_EVENT_SEQUENCE_DENIED);
-
- return;
-
-start_drag:
-
- gtk_widget_get_allocation (self->child, &child_alloc);
- gtk_widget_get_allocation (GTK_WIDGET (self->handle), &handle_alloc);
-
- if (self->position == GTK_POS_LEFT ||
- self->position == GTK_POS_RIGHT)
- {
- self->drag_orig_size = child_alloc.width + handle_alloc.width;
- gtk_widget_set_hexpand (self->child, FALSE);
- }
- else
- {
- self->drag_orig_size = child_alloc.height + handle_alloc.height;
- gtk_widget_set_vexpand (self->child, FALSE);
- }
-
- self->drag_position = self->drag_orig_size;
-
- gtk_widget_queue_resize (GTK_WIDGET (self));
-}
-
-static void
-egg_resizer_drag_update_cb (EggResizer *self,
- double offset_x,
- double offset_y,
- GtkGestureDrag *drag)
-{
- g_assert (EGG_IS_RESIZER (self));
- g_assert (GTK_IS_GESTURE_DRAG (drag));
-
- if (self->position == GTK_POS_LEFT)
- self->drag_position = self->drag_orig_size + offset_x;
- else if (self->position == GTK_POS_RIGHT)
- self->drag_position = gtk_widget_get_width (GTK_WIDGET (self)) - offset_x;
- else if (self->position == GTK_POS_TOP)
- self->drag_position = self->drag_orig_size + offset_y;
- else if (self->position == GTK_POS_BOTTOM)
- self->drag_position = gtk_widget_get_height (GTK_WIDGET (self)) - offset_y;
-
- gtk_widget_queue_resize (GTK_WIDGET (self));
-}
-
-static void
-egg_resizer_drag_end_cb (EggResizer *self,
- double offset_x,
- double offset_y,
- GtkGestureDrag *drag)
-{
- g_assert (EGG_IS_RESIZER (self));
- g_assert (GTK_IS_GESTURE_DRAG (drag));
-}
-
-GtkWidget *
-egg_resizer_new (GtkPositionType position)
-{
- EggResizer *self;
-
- self = g_object_new (EGG_TYPE_RESIZER, NULL);
- self->position = position;
- self->handle = EGG_HANDLE (egg_handle_new (position));
- gtk_widget_set_parent (GTK_WIDGET (self->handle), GTK_WIDGET (self));
-
- return GTK_WIDGET (self);
-}
-
-static void
-egg_resizer_measure (GtkWidget *widget,
- GtkOrientation orientation,
- int for_size,
- int *minimum,
- int *natural,
- int *minimum_baseline,
- int *natural_baseline)
-{
- EggResizer *self = (EggResizer *)widget;
-
- g_assert (EGG_IS_RESIZER (self));
-
- *minimum = 0;
- *natural = 0;
- *minimum_baseline = -1;
- *natural_baseline = -1;
-
- if (self->child != NULL)
- gtk_widget_measure (self->child,
- orientation,
- for_size,
- minimum, natural,
- NULL, NULL);
-
- if ((orientation == GTK_ORIENTATION_HORIZONTAL &&
- (self->position == GTK_POS_LEFT ||
- self->position == GTK_POS_RIGHT)) ||
- (orientation == GTK_ORIENTATION_VERTICAL &&
- (self->position == GTK_POS_TOP ||
- self->position == GTK_POS_BOTTOM)))
- {
- int handle_min, handle_nat;
-
- if (self->drag_position != 0)
- {
- if (self->drag_position > *minimum)
- *natural = self->drag_position;
- else if (self->drag_position < *minimum)
- *natural = *minimum;
- }
-
- if (gtk_widget_get_visible (GTK_WIDGET (self->handle)))
- {
- gtk_widget_measure (GTK_WIDGET (self->handle),
- orientation, for_size,
- &handle_min, &handle_nat,
- NULL, NULL);
-
- *minimum += handle_min;
- *natural += handle_nat;
- }
- }
-}
-
-static void
-egg_resizer_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline)
-{
- EggResizer *self = (EggResizer *)widget;
- GtkOrientation orientation;
- GtkAllocation child_alloc;
- GtkAllocation handle_alloc;
- int handle_min = 0, handle_nat = 0;
-
- g_assert (EGG_IS_RESIZER (self));
-
- if (self->position == GTK_POS_LEFT ||
- self->position == GTK_POS_RIGHT)
- orientation = GTK_ORIENTATION_HORIZONTAL;
- else
- orientation = GTK_ORIENTATION_VERTICAL;
-
- if (gtk_widget_get_visible (GTK_WIDGET (self->handle)))
- gtk_widget_measure (GTK_WIDGET (self->handle),
- orientation,
- -1,
- &handle_min, &handle_nat,
- NULL, NULL);
-
- switch (self->position)
- {
- case GTK_POS_LEFT:
- handle_alloc.x = width - handle_min;
- handle_alloc.width = handle_min;
- handle_alloc.y = 0;
- handle_alloc.height = height;
- child_alloc.x = 0;
- child_alloc.y = 0;
- child_alloc.width = width - handle_min;
- child_alloc.height = height;
- break;
-
- case GTK_POS_RIGHT:
- handle_alloc.x = 0;
- handle_alloc.width = handle_min;
- handle_alloc.y = 0;
- handle_alloc.height = height;
- child_alloc.x = handle_min;
- child_alloc.y = 0;
- child_alloc.width = width - handle_min;
- child_alloc.height = height;
- break;
-
- case GTK_POS_TOP:
- handle_alloc.x = 0;
- handle_alloc.width = width;
- handle_alloc.y = height - handle_min;
- handle_alloc.height = handle_min;
- child_alloc.x = 0;
- child_alloc.y = 0;
- child_alloc.width = width;
- child_alloc.height = height - handle_min;
- break;
-
- case GTK_POS_BOTTOM:
- handle_alloc.x = 0;
- handle_alloc.width = width;
- handle_alloc.y = 0;
- handle_alloc.height = handle_min;
- child_alloc.x = 0;
- child_alloc.y = handle_min;
- child_alloc.width = width;
- child_alloc.height = height - handle_min;
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- if (gtk_widget_get_mapped (GTK_WIDGET (self->handle)))
- gtk_widget_size_allocate (GTK_WIDGET (self->handle), &handle_alloc, -1);
-
- if (self->child != NULL &&
- gtk_widget_get_mapped (self->child))
- gtk_widget_size_allocate (self->child, &child_alloc, -1);
-}
-
-static void
-egg_resizer_compute_expand (GtkWidget *widget,
- gboolean *hexpand,
- gboolean *vexpand)
-{
- EggResizer *self = EGG_RESIZER (widget);
-
- if (self->child != NULL)
- {
- *hexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_HORIZONTAL);
- *vexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_VERTICAL);
- }
- else
- {
- *hexpand = FALSE;
- *vexpand = FALSE;
- }
-}
-
-static void
-egg_resizer_dispose (GObject *object)
-{
- EggResizer *self = (EggResizer *)object;
-
- if (self->handle)
- gtk_widget_unparent (GTK_WIDGET (self->handle));
- self->handle = NULL;
-
- if (self->child)
- gtk_widget_unparent (self->child);
- self->child = NULL;
-
- G_OBJECT_CLASS (egg_resizer_parent_class)->dispose (object);
-}
-
-static void
-egg_resizer_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- EggResizer *self = EGG_RESIZER (object);
-
- switch (prop_id)
- {
- case PROP_CHILD:
- g_value_set_object (value, egg_resizer_get_child (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-egg_resizer_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- EggResizer *self = EGG_RESIZER (object);
-
- switch (prop_id)
- {
- case PROP_CHILD:
- egg_resizer_set_child (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-egg_resizer_class_init (EggResizerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = egg_resizer_dispose;
- object_class->get_property = egg_resizer_get_property;
- object_class->set_property = egg_resizer_set_property;
-
- widget_class->compute_expand = egg_resizer_compute_expand;
- widget_class->measure = egg_resizer_measure;
- widget_class->size_allocate = egg_resizer_size_allocate;
-
- properties [PROP_CHILD] =
- g_param_spec_object ("child",
- "Child",
- "Child",
- GTK_TYPE_WIDGET,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- gtk_widget_class_set_css_name (widget_class, "eggresizer");
-}
-
-static void
-egg_resizer_init (EggResizer *self)
-{
- GtkGesture *gesture;
-
- gesture = gtk_gesture_drag_new ();
- gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_CAPTURE);
- g_signal_connect_object (gesture,
- "drag-begin",
- G_CALLBACK (egg_resizer_drag_begin_cb),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (gesture,
- "drag-update",
- G_CALLBACK (egg_resizer_drag_update_cb),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (gesture,
- "drag-end",
- G_CALLBACK (egg_resizer_drag_end_cb),
- self,
- G_CONNECT_SWAPPED);
- gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
-}
-
-/**
- * egg_resizer_get_child:
- * @self: a #EggResizer
- *
- * Gets the child widget of the resizer.
- *
- * Returns: (transfer none) (nullable): A #GtkWidget or %NULL
- */
-GtkWidget *
-egg_resizer_get_child (EggResizer *self)
-{
- g_return_val_if_fail (EGG_IS_RESIZER (self), NULL);
-
- return self->child;
-}
-
-void
-egg_resizer_set_child (EggResizer *self,
- GtkWidget *child)
-{
- g_return_if_fail (EGG_IS_RESIZER (self));
- g_return_if_fail (!child || GTK_IS_WIDGET (child));
-
- if (child == self->child)
- return;
-
- g_clear_pointer (&self->child, gtk_widget_unparent);
-
- self->child = child;
-
- if (self->child != NULL)
- gtk_widget_insert_before (self->child,
- GTK_WIDGET (self),
- GTK_WIDGET (self->handle));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CHILD]);
-}
-
-GtkPositionType
-egg_resizer_get_position (EggResizer *self)
-{
- g_return_val_if_fail (EGG_IS_RESIZER (self), 0);
-
- return self->position;
-}
-
-void
-egg_resizer_set_position (EggResizer *self,
- GtkPositionType position)
-{
- g_return_if_fail (EGG_IS_RESIZER (self));
-
- if (position != self->position)
- {
- self->position = position;
-
- egg_handle_set_position (self->handle, position);
- gtk_widget_queue_resize (GTK_WIDGET (self));
- }
-}
-
-GtkWidget *
-egg_resizer_get_handle (EggResizer *self)
-{
- g_return_val_if_fail (EGG_IS_RESIZER (self), NULL);
-
- return GTK_WIDGET (self->handle);
-}
diff --git a/src/libsysprof-ui/libsysprof-ui.gresource.xml b/src/libsysprof-ui/libsysprof-ui.gresource.xml
deleted file mode 100644
index e5aa0593..00000000
--- a/src/libsysprof-ui/libsysprof-ui.gresource.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
- css/SysprofEnvironEditor-shared.css
- css/SysprofDisplay-shared.css
- css/SysprofProfilerAssistant-shared.css
-
-
- ../../data/icons/org.gnome.Sysprof.svg
- ../../data/icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg
- ../../data/icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg
-
-
-
- sysprof-aid-icon.ui
- sysprof-callgraph-page.ui
- sysprof-details-page.ui
- sysprof-display.ui
- sysprof-environ-editor-row.ui
- sysprof-failed-state-view.ui
- sysprof-logs-page.ui
- sysprof-marks-page.ui
- sysprof-memprof-page.ui
- sysprof-process-model-row.ui
- sysprof-profiler-assistant.ui
- sysprof-recording-state-view.ui
- sysprof-tab.ui
- sysprof-visualizers-frame.ui
-
-
diff --git a/src/libsysprof-ui/meson.build b/src/libsysprof-ui/meson.build
deleted file mode 100644
index 0017eedb..00000000
--- a/src/libsysprof-ui/meson.build
+++ /dev/null
@@ -1,136 +0,0 @@
-libsysprof_ui_public_sources = [
- 'sysprof-check.c',
- 'sysprof-display.c',
- 'sysprof-model-filter.c',
- 'sysprof-notebook.c',
- 'sysprof-page.c',
- 'sysprof-process-model-row.c',
- 'sysprof-visualizer.c',
- 'sysprof-visualizer-group.c',
- 'sysprof-zoom-manager.c',
-]
-
-libsysprof_ui_private_sources = [
- 'egg-handle.c',
- 'egg-paned.c',
- 'egg-resizer.c',
-
- 'pointcache.c',
- 'rectangles.c',
- 'sysprof-aid.c',
- 'sysprof-aid-icon.c',
- 'sysprof-battery-aid.c',
- 'sysprof-cairo.c',
- 'sysprof-callgraph-aid.c',
- 'sysprof-callgraph-page.c',
- 'sysprof-cell-renderer-duration.c',
- 'sysprof-cell-renderer-percent.c',
- 'sysprof-cell-renderer-progress.c',
- 'sysprof-color-cycle.c',
- 'sysprof-counters-aid.c',
- 'sysprof-cpu-aid.c',
- 'sysprof-depth-visualizer.c',
- 'sysprof-details-page.c',
- 'sysprof-diskstat-aid.c',
- 'sysprof-display.c',
- 'sysprof-duplex-visualizer.c',
- 'sysprof-environ.c',
- 'sysprof-environ-editor.c',
- 'sysprof-environ-editor-row.c',
- 'sysprof-environ-variable.c',
- 'sysprof-failed-state-view.c',
- 'sysprof-line-visualizer.c',
- 'sysprof-log-model.c',
- 'sysprof-logs-aid.c',
- 'sysprof-logs-page.c',
- 'sysprof-mark-detail.c',
- 'sysprof-marks-aid.c',
- 'sysprof-marks-model.c',
- 'sysprof-marks-page.c',
- 'sysprof-mark-visualizer.c',
- 'sysprof-memory-aid.c',
- 'sysprof-memprof-aid.c',
- 'sysprof-memprof-page.c',
- 'sysprof-memprof-visualizer.c',
- 'sysprof-netdev-aid.c',
- 'sysprof-procs-visualizer.c',
- 'sysprof-profiler-assistant.c',
- 'sysprof-proxy-aid.c',
- 'sysprof-rapl-aid.c',
- 'sysprof-recording-state-view.c',
- 'sysprof-scrollmap.c',
- 'sysprof-tab.c',
- 'sysprof-theme-manager.c',
- 'sysprof-time-label.c',
- 'sysprof-time-visualizer.c',
- 'sysprof-visualizer-group-header.c',
- 'sysprof-visualizers-frame.c',
- 'sysprof-visualizer-ticks.c',
- '../stackstash.c',
-]
-
-libsysprof_ui_public_headers = [
- 'sysprof-check.h',
- 'sysprof-display.h',
- 'sysprof-model-filter.h',
- 'sysprof-notebook.h',
- 'sysprof-page.h',
- 'sysprof-process-model-row.h',
- 'sysprof-visualizer.h',
- 'sysprof-visualizer-group.h',
- 'sysprof-zoom-manager.h',
- 'sysprof-ui.h',
-]
-
-libsysprof_ui_resources = gnome.compile_resources(
- 'libsysprof-ui-resources',
- 'libsysprof-ui.gresource.xml',
- c_name: 'lisysprof_ui',
-)
-
-# Subset of dependencies used in generating the pkg-config file
-libsysprof_ui_pkg_deps = [
- dependency('gio-2.0', version: glib_req_version),
- dependency('gtk4', version: gtk_req_version),
- dependency('libadwaita-1'),
-]
-
-libsysprof_ui_deps = libsysprof_ui_pkg_deps + [
- libsysprof_dep,
-]
-
-# Meson's pkgconfig module wants to see a library here, not an internal
-# dependency object
-libsysprof_ui_pkg_deps += libsysprof
-
-libsysprof_ui = shared_library(
- 'sysprof-ui-@0@'.format(libsysprof_ui_api_version),
- libsysprof_ui_public_sources + libsysprof_ui_private_sources + libsysprof_ui_resources,
-
- dependencies: libsysprof_ui_deps + [librax_dep],
- install_dir: get_option('libdir'),
- install: true,
- c_args: [ '-DSYSPROF_UI_COMPILATION' ],
- gnu_symbol_visibility: 'hidden',
-)
-
-libsysprof_ui_dep = declare_dependency(
- link_with: libsysprof_ui,
- dependencies: libsysprof_ui_deps,
- include_directories: include_directories('.'),
-)
-meson.override_dependency('sysprof-ui-@0@'.format(libsysprof_api_version), libsysprof_ui_dep)
-
-pkgconfig.generate(
- libsysprof_ui,
- subdirs: [ sysprof_ui_header_subdir ],
- description: 'The UI library for GTK applications embedding sysprof',
- install_dir: join_paths(get_option('libdir'), 'pkgconfig'),
- requires: [ 'gio-2.0', 'gtk4' ],
- libraries_private: libsysprof_ui_pkg_deps,
- variables: [
- 'datadir=' + datadir_for_pc_file,
- ],
-)
-
-install_headers(libsysprof_ui_public_headers, subdir: sysprof_ui_header_subdir)
diff --git a/src/libsysprof-ui/pointcache.c b/src/libsysprof-ui/pointcache.c
deleted file mode 100644
index c16304ff..00000000
--- a/src/libsysprof-ui/pointcache.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* pointcache.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "pointcache"
-
-#include "pointcache.h"
-
-struct _PointCache
-{
- volatile gint ref_count;
- GHashTable *sets;
-};
-
-static void
-point_cache_finalize (PointCache *self)
-{
- g_clear_pointer (&self->sets, g_hash_table_unref);
- g_slice_free (PointCache, self);
-}
-
-PointCache *
-point_cache_ref (PointCache *self)
-{
- g_return_val_if_fail (self != NULL, NULL);
- g_return_val_if_fail (self->ref_count > 0, NULL);
-
- g_atomic_int_inc (&self->ref_count);
-
- return self;
-}
-
-void
-point_cache_unref (PointCache *self)
-{
- g_return_if_fail (self != NULL);
- g_return_if_fail (self->ref_count > 0);
-
- if (g_atomic_int_dec_and_test (&self->ref_count))
- point_cache_finalize (self);
-}
-
-PointCache *
-point_cache_new (void)
-{
- PointCache *self;
-
- self = g_slice_new0 (PointCache);
- self->ref_count = 1;
- self->sets = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_array_unref);
-
- return self;
-}
-
-void
-point_cache_add_set (PointCache *self,
- guint set_id)
-{
- g_hash_table_insert (self->sets,
- GUINT_TO_POINTER (set_id),
- g_array_new (FALSE, FALSE, sizeof (Point)));
-}
-
-gboolean
-point_cache_contains_set (PointCache *self,
- guint set_id)
-{
- return g_hash_table_contains (self->sets, GUINT_TO_POINTER (set_id));
-}
-
-void
-point_cache_add_point_to_set (PointCache *self,
- guint set_id,
- gdouble x,
- gdouble y)
-{
- GArray *ar;
- Point point = { x, y };
-
- ar = g_hash_table_lookup (self->sets, GUINT_TO_POINTER (set_id));
- g_array_append_val (ar, point);
-}
-
-const Point *
-point_cache_get_points (PointCache *self,
- guint set_id,
- guint *n_points)
-{
- GArray *ar;
-
- *n_points = 0;
-
- if ((ar = g_hash_table_lookup (self->sets, GUINT_TO_POINTER (set_id))))
- {
- *n_points = ar->len;
- return &g_array_index (ar, const Point, 0);
- }
-
- return NULL;
-}
diff --git a/src/libsysprof-ui/pointcache.h b/src/libsysprof-ui/pointcache.h
deleted file mode 100644
index 3aed8179..00000000
--- a/src/libsysprof-ui/pointcache.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* pointcache.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-typedef struct _PointCache PointCache;
-
-typedef struct
-{
- gdouble x;
- gdouble y;
-} Point;
-
-PointCache *point_cache_new (void);
-PointCache *point_cache_ref (PointCache *self);
-void point_cache_unref (PointCache *self);
-void point_cache_add_set (PointCache *self,
- guint set_id);
-gboolean point_cache_contains_set (PointCache *self,
- guint set_id);
-void point_cache_add_point_to_set (PointCache *self,
- guint set_id,
- gdouble x,
- gdouble y);
-const Point *point_cache_get_points (PointCache *self,
- guint set_id,
- guint *n_points);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (PointCache, point_cache_unref)
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/rectangles.c b/src/libsysprof-ui/rectangles.c
deleted file mode 100644
index 9db41038..00000000
--- a/src/libsysprof-ui/rectangles.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/* rectangles.c
- *
- * Copyright 2018-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "rectangles.h"
-#include "sysprof-color-cycle.h"
-#include "sysprof-visualizer.h"
-
-typedef struct
-{
- const gchar *name;
- const gchar *message;
- gint64 begin;
- gint64 end;
- GdkRectangle area;
-} Rectangle;
-
-struct _Rectangles
-{
- GStringChunk *strings;
- GArray *rectangles;
- GHashTable *y_indexes;
- GHashTable *colors;
- SysprofColorCycle *cycle;
- gint64 begin_time;
- gint64 end_time;
- guint sorted : 1;
-};
-
-Rectangles *
-rectangles_new (gint64 begin_time,
- gint64 end_time)
-{
- Rectangles *self;
-
- self = g_slice_new0 (Rectangles);
- self->strings = g_string_chunk_new (4096);
- self->rectangles = g_array_new (FALSE, FALSE, sizeof (Rectangle));
- self->y_indexes = g_hash_table_new (g_str_hash, g_str_equal);
- self->colors = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
- self->cycle = sysprof_color_cycle_new ();
- self->begin_time = begin_time;
- self->end_time = end_time;
- self->sorted = FALSE;
-
- return self;
-}
-
-void
-rectangles_add (Rectangles *self,
- gint64 begin_time,
- gint64 end_time,
- const gchar *name,
- const gchar *message)
-{
- Rectangle rect = {0};
-
- g_assert (self != NULL);
-
- if (message != NULL)
- rect.message = g_string_chunk_insert_const (self->strings, message);
-
- if (name != NULL)
- rect.name = g_string_chunk_insert_const (self->strings, name);
-
- rect.begin = begin_time;
- rect.end = end_time;
-
- if (rect.end == rect.begin)
- rect.area.width = 1;
-
- g_array_append_val (self->rectangles, rect);
-
- self->sorted = FALSE;
-}
-
-void
-rectangles_free (Rectangles *self)
-{
- g_string_chunk_free (self->strings);
- g_array_unref (self->rectangles);
- g_hash_table_unref (self->colors);
- g_hash_table_unref (self->y_indexes);
- sysprof_color_cycle_unref (self->cycle);
- g_slice_free (Rectangles, self);
-}
-
-static gint
-sort_rectangles (gconstpointer a,
- gconstpointer b)
-{
- const Rectangle *r1 = a;
- const Rectangle *r2 = b;
- gint64 r = r1->begin - r2->begin;
- if (r == 0)
- r = r1->end - r2->end;
- if (r > 0) return 1;
- else if (r < 0) return -1;
- else return 0;
-}
-
-static void
-rectangles_sort (Rectangles *self)
-{
- guint sequence = 0;
-
- g_assert (self != NULL);
-
- if (self->sorted)
- return;
-
- g_array_sort (self->rectangles, sort_rectangles);
-
- g_hash_table_remove_all (self->y_indexes);
-
- for (guint i = 0; i < self->rectangles->len; i++)
- {
- const Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
-
- if (!g_hash_table_contains (self->y_indexes, rect->name))
- {
- GdkRGBA rgba;
-
- sysprof_color_cycle_next (self->cycle, &rgba);
- g_hash_table_insert (self->y_indexes, (gchar *)rect->name, GUINT_TO_POINTER (++sequence));
- g_hash_table_insert (self->colors, (gchar *)rect->name, g_memdup2 (&rgba, sizeof rgba));
- }
- }
-
- self->sorted = TRUE;
-}
-
-void
-rectangles_draw (Rectangles *self,
- GtkWidget *row,
- cairo_t *cr)
-{
- GtkAllocation alloc;
- gdouble range;
- guint ns;
-
- g_assert (self != NULL);
- g_assert (SYSPROF_IS_VISUALIZER (row));
- g_assert (cr != NULL);
-
- if (!self->sorted)
- rectangles_sort (self);
-
- gtk_widget_get_allocation (row, &alloc);
- ns = g_hash_table_size (self->y_indexes);
- if (ns == 0 || alloc.height == 0)
- return;
-
- range = self->end_time - self->begin_time;
-
- for (guint i = 0; i < self->rectangles->len; i++)
- {
- Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
- guint y_index = GPOINTER_TO_UINT (g_hash_table_lookup (self->y_indexes, rect->name));
- SysprofVisualizerRelativePoint in_points[2];
- SysprofVisualizerAbsolutePoint out_points[2];
- GdkRectangle r;
- GdkRGBA *rgba;
-
- g_assert (y_index > 0);
- g_assert (y_index <= ns);
-
- in_points[0].x = (rect->begin - self->begin_time) / range;
- in_points[0].y = (y_index - 1) / (gdouble)ns;
- in_points[1].x = (rect->end - self->begin_time) / range;
- in_points[1].y = 0;
-
- sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (row),
- in_points, G_N_ELEMENTS (in_points),
- out_points, G_N_ELEMENTS (out_points));
-
- r.height = alloc.height / (gdouble)ns;
- r.x = out_points[0].x;
- r.y = out_points[0].y - r.height;
-
- if (rect->end <= rect->begin)
- r.width = 1;
- else
- r.width = MAX (1, out_points[1].x - out_points[0].x);
-
- rect->area = r;
-
- rgba = g_hash_table_lookup (self->colors, rect->name);
-
- gdk_cairo_rectangle (cr, &r);
- gdk_cairo_set_source_rgba (cr, rgba);
- cairo_fill (cr);
- }
-}
-
-void
-rectangles_set_end_time (Rectangles *self,
- gint64 end_time)
-{
- /* We might not know the real end time until we've exhausted the stream */
- self->end_time = end_time;
-}
-
-gboolean
-rectangles_query_tooltip (Rectangles *self,
- GtkTooltip *tooltip,
- const gchar *group,
- gint x,
- gint y)
-{
- g_assert (self != NULL);
- g_assert (GTK_IS_TOOLTIP (tooltip));
-
- /* TODO: Sort, binary search, etc. */
-
- for (guint i = 0; i < self->rectangles->len; i++)
- {
- const Rectangle *r = &g_array_index (self->rectangles, Rectangle, i);
-
- if (r->area.x <= x &&
- r->area.y <= y &&
- r->area.x + r->area.width >= x &&
- r->area.y + r->area.height >= y)
- {
- g_autofree gchar *text = g_strdup_printf ("%s:%s: %s", group, r->name, r->message);
- gtk_tooltip_set_text (tooltip, text);
- return TRUE;
- }
- }
-
- return FALSE;
-}
diff --git a/src/libsysprof-ui/rectangles.h b/src/libsysprof-ui/rectangles.h
deleted file mode 100644
index f71c3a43..00000000
--- a/src/libsysprof-ui/rectangles.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* rectangles.h
- *
- * Copyright 2018-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-typedef struct _Rectangles Rectangles;
-
-Rectangles *rectangles_new (gint64 begin_time,
- gint64 end_time);
-void rectangles_free (Rectangles *self);
-void rectangles_draw (Rectangles *self,
- GtkWidget *widget,
- cairo_t *cr);
-void rectangles_add (Rectangles *self,
- gint64 begin_time,
- gint64 end_time,
- const gchar *name,
- const gchar *message);
-void rectangles_set_end_time (Rectangles *self,
- gint64 end_time);
-gboolean rectangles_query_tooltip (Rectangles *self,
- GtkTooltip *tooltip,
- const gchar *group,
- gint x,
- gint y);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-aid-icon.c b/src/libsysprof-ui/sysprof-aid-icon.c
deleted file mode 100644
index eba2b4ff..00000000
--- a/src/libsysprof-ui/sysprof-aid-icon.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/* sysprof-aid-icon.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-aid-icon"
-
-#include "config.h"
-
-#include "sysprof-aid-icon.h"
-
-struct _SysprofAidIcon
-{
- GtkFlowBoxChild parent_instance;
-
- SysprofAid *aid;
-
- /* Template Objects */
- GtkLabel *label;
- GtkImage *image;
- GtkImage *check;
-};
-
-G_DEFINE_TYPE (SysprofAidIcon, sysprof_aid_icon, GTK_TYPE_FLOW_BOX_CHILD)
-
-enum {
- PROP_0,
- PROP_AID,
- PROP_SELECTED,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-/**
- * sysprof_aid_icon_new:
- *
- * Create a new #SysprofAidIcon.
- *
- * Returns: (transfer full): a newly created #SysprofAidIcon
- */
-GtkWidget *
-sysprof_aid_icon_new (SysprofAid *aid)
-{
- g_return_val_if_fail (SYSPROF_IS_AID (aid), NULL);
-
- return g_object_new (SYSPROF_TYPE_AID_ICON,
- "aid", aid,
- NULL);
-}
-
-gboolean
-sysprof_aid_icon_is_selected (SysprofAidIcon *self)
-{
- g_return_val_if_fail (SYSPROF_IS_AID_ICON (self), FALSE);
-
- return gtk_widget_get_visible (GTK_WIDGET (self->check));
-}
-
-/**
- * sysprof_aid_icon_get_aid:
- *
- * Get the aid that is represented by the icon.
- *
- * Returns: (transfer none): a #SysprofAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_aid_icon_get_aid (SysprofAidIcon *self)
-{
- g_return_val_if_fail (SYSPROF_IS_AID_ICON (self), NULL);
-
- return self->aid;
-}
-
-static void
-sysprof_aid_icon_set_aid (SysprofAidIcon *self,
- SysprofAid *aid)
-{
- g_return_if_fail (SYSPROF_IS_AID_ICON (self));
- g_return_if_fail (SYSPROF_IS_AID (aid));
-
- if (g_set_object (&self->aid, aid))
- {
- GIcon *icon = sysprof_aid_get_icon (aid);
- const gchar *title = sysprof_aid_get_display_name (aid);
-
- g_object_set (self->image, "gicon", icon, NULL);
- gtk_label_set_label (self->label, title);
- }
-}
-
-static void
-sysprof_aid_icon_finalize (GObject *object)
-{
- SysprofAidIcon *self = (SysprofAidIcon *)object;
-
- g_clear_object (&self->aid);
-
- G_OBJECT_CLASS (sysprof_aid_icon_parent_class)->finalize (object);
-}
-
-static void
-sysprof_aid_icon_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofAidIcon *self = SYSPROF_AID_ICON (object);
-
- switch (prop_id)
- {
- case PROP_AID:
- g_value_set_object (value, sysprof_aid_icon_get_aid (self));
- break;
-
- case PROP_SELECTED:
- g_value_set_boolean (value, gtk_widget_get_visible (GTK_WIDGET (self->check)));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_aid_icon_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofAidIcon *self = SYSPROF_AID_ICON (object);
-
- switch (prop_id)
- {
- case PROP_AID:
- sysprof_aid_icon_set_aid (self, g_value_get_object (value));
- break;
-
- case PROP_SELECTED:
- gtk_widget_set_visible (GTK_WIDGET (self->check), g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_aid_icon_class_init (SysprofAidIconClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->finalize = sysprof_aid_icon_finalize;
- object_class->get_property = sysprof_aid_icon_get_property;
- object_class->set_property = sysprof_aid_icon_set_property;
-
- properties [PROP_AID] =
- g_param_spec_object ("aid",
- "Aid",
- "The aid for the icon",
- SYSPROF_TYPE_AID,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_SELECTED] =
- g_param_spec_boolean ("selected",
- "Selected",
- "If the item is selected",
- FALSE,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- gtk_widget_class_set_css_name (widget_class, "sysprofaidicon");
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-aid-icon.ui");
- gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, check);
- gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, image);
- gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, label);
-}
-
-static void
-sysprof_aid_icon_init (SysprofAidIcon *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-}
-
-void
-sysprof_aid_icon_toggle (SysprofAidIcon *self)
-{
- g_return_if_fail (SYSPROF_IS_AID_ICON (self));
-
- gtk_widget_set_visible (GTK_WIDGET (self->check),
- !gtk_widget_get_visible (GTK_WIDGET (self->check)));
-}
diff --git a/src/libsysprof-ui/sysprof-aid-icon.ui b/src/libsysprof-ui/sysprof-aid-icon.ui
deleted file mode 100644
index 491cb405..00000000
--- a/src/libsysprof-ui/sysprof-aid-icon.ui
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-aid.c b/src/libsysprof-ui/sysprof-aid.c
deleted file mode 100644
index 1bf3a489..00000000
--- a/src/libsysprof-ui/sysprof-aid.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/* sysprof-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-aid.h"
-
-typedef struct
-{
- GPtrArray *sources;
- gchar *display_name;
- GIcon *icon;
-} SysprofAidPrivate;
-
-static void buildable_iface_init (GtkBuildableIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (SysprofAid, sysprof_aid, G_TYPE_OBJECT,
- G_ADD_PRIVATE (SysprofAid)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
-
-enum {
- PROP_0,
- PROP_DISPLAY_NAME,
- PROP_ICON,
- PROP_ICON_NAME,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-static void
-sysprof_aid_real_present_async (SysprofAid *self,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_task_report_new_error (self, callback, user_data,
- sysprof_aid_real_present_async,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "Not supported");
-}
-
-static gboolean
-sysprof_aid_real_present_finish (SysprofAid *self,
- GAsyncResult *result,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_aid_finalize (GObject *object)
-{
- SysprofAid *self = (SysprofAid *)object;
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_clear_pointer (&priv->sources, g_ptr_array_unref);
- g_clear_pointer (&priv->display_name, g_free);
- g_clear_object (&priv->icon);
-
- G_OBJECT_CLASS (sysprof_aid_parent_class)->finalize (object);
-}
-
-static void
-sysprof_aid_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofAid *self = SYSPROF_AID (object);
-
- switch (prop_id)
- {
- case PROP_DISPLAY_NAME:
- g_value_set_string (value, sysprof_aid_get_display_name (self));
- break;
-
- case PROP_ICON:
- g_value_set_object (value, sysprof_aid_get_icon (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_aid_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofAid *self = SYSPROF_AID (object);
-
- switch (prop_id)
- {
- case PROP_DISPLAY_NAME:
- sysprof_aid_set_display_name (self, g_value_get_string (value));
- break;
-
- case PROP_ICON:
- sysprof_aid_set_icon (self, g_value_get_object (value));
- break;
-
- case PROP_ICON_NAME:
- sysprof_aid_set_icon_name (self, g_value_get_string (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_aid_class_init (SysprofAidClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_aid_finalize;
- object_class->get_property = sysprof_aid_get_property;
- object_class->set_property = sysprof_aid_set_property;
-
- klass->present_async = sysprof_aid_real_present_async;
- klass->present_finish = sysprof_aid_real_present_finish;
-
- properties [PROP_DISPLAY_NAME] =
- g_param_spec_string ("display-name",
- "Display Name",
- "Display Name",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_ICON_NAME] =
- g_param_spec_string ("icon-name",
- "Icon Name",
- "Icon Name",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_ICON] =
- g_param_spec_object ("icon",
- "Icon",
- "The icon to display",
- G_TYPE_ICON,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-sysprof_aid_init (SysprofAid *self G_GNUC_UNUSED)
-{
-}
-
-/**
- * sysprof_aid_get_display_name:
- * @self: a #SysprofAid
- *
- * Gets the display name as it should be shown to the user.
- *
- * Returns: a string containing the display name
- *
- * Since: 3.34
- */
-const gchar *
-sysprof_aid_get_display_name (SysprofAid *self)
-{
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_AID (self), NULL);
-
- return priv->display_name;
-}
-
-/**
- * sysprof_aid_get_icon:
- *
- * Gets the icon for the aid.
- *
- * Returns: (transfer none) (nullable): a #GIcon or %NULL
- *
- * Since: 3.34
- */
-GIcon *
-sysprof_aid_get_icon (SysprofAid *self)
-{
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_AID (self), NULL);
-
- return priv->icon;
-}
-
-void
-sysprof_aid_set_icon (SysprofAid *self,
- GIcon *icon)
-{
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_AID (self));
-
- if (g_set_object (&priv->icon, icon))
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]);
-}
-
-void
-sysprof_aid_set_icon_name (SysprofAid *self,
- const gchar *icon_name)
-{
- g_autoptr(GIcon) icon = NULL;
-
- g_return_if_fail (SYSPROF_IS_AID (self));
-
- if (icon_name != NULL)
- icon = g_themed_icon_new (icon_name);
-
- sysprof_aid_set_icon (self, icon);
-}
-
-void
-sysprof_aid_set_display_name (SysprofAid *self,
- const gchar *display_name)
-{
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_AID (self));
-
- if (g_strcmp0 (display_name, priv->display_name) != 0)
- {
- g_free (priv->display_name);
- priv->display_name = g_strdup (display_name);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
- }
-}
-
-void
-sysprof_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_AID (self));
- g_return_if_fail (SYSPROF_IS_PROFILER (profiler));
-
- if (priv->sources != NULL)
- {
- for (guint i = 0; i < priv->sources->len; i++)
- {
- SysprofSource *source = g_ptr_array_index (priv->sources, i);
-
- sysprof_profiler_add_source (profiler, source);
- }
-
- if (priv->sources->len > 0)
- g_ptr_array_remove_range (priv->sources, 0, priv->sources->len);
- }
-
- if (SYSPROF_AID_GET_CLASS (self)->prepare)
- SYSPROF_AID_GET_CLASS (self)->prepare (self, profiler);
-}
-
-static void
-sysprof_aid_add_child (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *object,
- const gchar *type G_GNUC_UNUSED)
-{
- SysprofAid *self = (SysprofAid *)buildable;
- SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
-
- g_assert (SYSPROF_IS_AID (self));
- g_assert (GTK_IS_BUILDER (builder));
- g_assert (G_IS_OBJECT (object));
-
- if (SYSPROF_IS_SOURCE (object))
- {
- if (priv->sources == NULL)
- priv->sources = g_ptr_array_new_with_free_func (g_object_unref);
- g_ptr_array_add (priv->sources, g_object_ref (object));
- return;
- }
-
- g_warning ("Unsupported child type of %s: %s",
- G_OBJECT_TYPE_NAME (self),
- G_OBJECT_TYPE_NAME (object));
-}
-
-static void
-buildable_iface_init (GtkBuildableIface *iface)
-{
- iface->add_child = sysprof_aid_add_child;
-}
-
-SysprofAid *
-sysprof_aid_new (const gchar *display_name,
- const gchar *icon_name)
-{
- return g_object_new (SYSPROF_TYPE_AID,
- "display-aid", display_name,
- "icon-name", icon_name,
- NULL);
-}
-
-void
-sysprof_aid_present_async (SysprofAid *self,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_return_if_fail (SYSPROF_IS_AID (self));
- g_return_if_fail (reader != NULL);
- g_return_if_fail (SYSPROF_IS_DISPLAY (display));
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- SYSPROF_AID_GET_CLASS (self)->present_async (self, reader, display, cancellable, callback, user_data);
-}
-
-gboolean
-sysprof_aid_present_finish (SysprofAid *self,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_AID (self), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
-
- return SYSPROF_AID_GET_CLASS (self)->present_finish (self, result, error);
-}
diff --git a/src/libsysprof-ui/sysprof-aid.h b/src/libsysprof-ui/sysprof-aid.h
deleted file mode 100644
index 70a16667..00000000
--- a/src/libsysprof-ui/sysprof-aid.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* sysprof-aid.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-#include
-
-#include "sysprof-display.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_AID (sysprof_aid_get_type())
-
-G_DECLARE_DERIVABLE_TYPE (SysprofAid, sysprof_aid, SYSPROF, AID, GObject)
-
-struct _SysprofAidClass
-{
- GObjectClass parent_class;
-
- void (*prepare) (SysprofAid *self,
- SysprofProfiler *profiler);
- void (*present_async) (SysprofAid *self,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
- gboolean (*present_finish) (SysprofAid *self,
- GAsyncResult *result,
- GError **error);
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-SysprofAid *sysprof_aid_new (const gchar *display_name,
- const gchar *icon_name);
-const gchar *sysprof_aid_get_display_name (SysprofAid *self);
-void sysprof_aid_set_display_name (SysprofAid *self,
- const gchar *display_name);
-GIcon *sysprof_aid_get_icon (SysprofAid *self);
-void sysprof_aid_set_icon (SysprofAid *self,
- GIcon *icon);
-void sysprof_aid_set_icon_name (SysprofAid *self,
- const gchar *icon_name);
-void sysprof_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler);
-void sysprof_aid_present_async (SysprofAid *self,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean sysprof_aid_present_finish (SysprofAid *self,
- GAsyncResult *result,
- GError **error);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-battery-aid.c b/src/libsysprof-ui/sysprof-battery-aid.c
deleted file mode 100644
index 9351200f..00000000
--- a/src/libsysprof-ui/sysprof-battery-aid.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/* sysprof-battery-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-battery-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-battery-aid.h"
-#include "sysprof-line-visualizer.h"
-
-struct _SysprofBatteryAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
-} Present;
-
-G_DEFINE_TYPE (SysprofBatteryAid, sysprof_battery_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-/**
- * sysprof_battery_aid_new:
- *
- * Create a new #SysprofBatteryAid.
- *
- * Returns: (transfer full): a newly created #SysprofBatteryAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_battery_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_BATTERY_AID, NULL);
-}
-
-static void
-sysprof_battery_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
-#ifdef __linux__
- g_autoptr(SysprofSource) source = NULL;
-
- g_assert (SYSPROF_IS_BATTERY_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- source = sysprof_battery_source_new ();
- sysprof_profiler_add_source (profiler, source);
-#endif
-}
-
-static bool
-collect_battery_counters (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
- GArray *counters = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
- g_assert (counters != NULL);
-
- for (guint i = 0; i < def->n_counters; i++)
- {
- const SysprofCaptureCounter *counter = &def->counters[i];
-
- if (g_strcmp0 (counter->category, "Battery Charge") == 0)
- g_array_append_vals (counters, counter, 1);
- }
-
- return TRUE;
-}
-
-static void
-sysprof_battery_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *present = task_data;
- g_autoptr(GArray) counters = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_BATTERY_AID (source_object));
- g_assert (present != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
- sysprof_capture_cursor_foreach (present->cursor, collect_battery_counters, counters);
- g_task_return_pointer (task,
- g_steal_pointer (&counters),
- (GDestroyNotify) g_array_unref);
-}
-
-static void
-sysprof_battery_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_BATTERY_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (1, types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_battery_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_battery_aid_present_worker);
-}
-
-static gboolean
-sysprof_battery_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- g_autoptr(GArray) counters = NULL;
- Present *present;
-
- g_assert (SYSPROF_IS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- present = g_task_get_task_data (G_TASK (result));
-
- if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
- {
- g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
- SysprofVisualizerGroup *group;
- guint found = 0;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "title", _("Battery Charge"),
- "visible", TRUE,
- NULL);
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
-
- if (g_strcmp0 (ctr->category, "Battery Charge") == 0)
- {
- g_autofree gchar *title = NULL;
- gboolean is_combined = g_str_equal (ctr->name, "Combined");
- GtkWidget *row;
- GdkRGBA rgba;
-
- if (is_combined)
- title = g_strdup (_("Battery Charge (All)"));
- else
- title = g_strdup_printf ("Battery Charge (%s)", ctr->name);
-
- row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- "title", title,
- "height-request", 35,
- "visible", is_combined,
- NULL);
- sysprof_color_cycle_next (cycle, &rgba);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- sysprof_visualizer_group_insert (group,
- SYSPROF_VISUALIZER (row),
- is_combined ? 0 : -1,
- !is_combined);
-
- found++;
- }
- }
-
- if (found > 0)
- sysprof_display_add_group (present->display, group);
- else
- g_object_unref (g_object_ref_sink (group));
- }
-
- return counters != NULL;
-}
-
-static void
-sysprof_battery_aid_class_init (SysprofBatteryAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_battery_aid_prepare;
- aid_class->present_async = sysprof_battery_aid_present_async;
- aid_class->present_finish = sysprof_battery_aid_present_finish;
-}
-
-static void
-sysprof_battery_aid_init (SysprofBatteryAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Battery"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "battery-low-charging-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-cairo.c b/src/libsysprof-ui/sysprof-cairo.c
deleted file mode 100644
index 3d8f82a6..00000000
--- a/src/libsysprof-ui/sysprof-cairo.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/* sysprof-cairo.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "config.h"
-
-#include "sysprof-ui-private.h"
-
-void
-_sysprof_rounded_rectangle (cairo_t *cr,
- const GdkRectangle *rect,
- gint x_radius,
- gint y_radius)
-{
- gint x;
- gint y;
- gint width;
- gint height;
- gint x1, x2;
- gint y1, y2;
- gint xr1, xr2;
- gint yr1, yr2;
-
- g_return_if_fail (cr);
- g_return_if_fail (rect);
-
- x = rect->x;
- y = rect->y;
- width = rect->width;
- height = rect->height;
-
- x1 = x;
- x2 = x1 + width;
- y1 = y;
- y2 = y1 + height;
-
- x_radius = MIN (x_radius, width / 2.0);
- y_radius = MIN (y_radius, width / 2.0);
-
- xr1 = x_radius;
- xr2 = x_radius / 2.0;
- yr1 = y_radius;
- yr2 = y_radius / 2.0;
-
- cairo_move_to (cr, x1 + xr1, y1);
- cairo_line_to (cr, x2 - xr1, y1);
- cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
- cairo_line_to (cr, x2, y2 - yr1);
- cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
- cairo_line_to (cr, x1 + xr1, y2);
- cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
- cairo_line_to (cr, x1, y1 + yr1);
- cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
- cairo_close_path (cr);
-}
diff --git a/src/libsysprof-ui/sysprof-callgraph-aid.c b/src/libsysprof-ui/sysprof-callgraph-aid.c
deleted file mode 100644
index f12be766..00000000
--- a/src/libsysprof-ui/sysprof-callgraph-aid.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/* sysprof-callgraph-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-callgraph-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-callgraph-aid.h"
-#include "sysprof-callgraph-page.h"
-#include "sysprof-depth-visualizer.h"
-
-struct _SysprofCallgraphAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
- guint has_samples : 1;
-} Present;
-
-G_DEFINE_TYPE (SysprofCallgraphAid, sysprof_callgraph_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-static void
-on_group_activated_cb (SysprofVisualizerGroup *group,
- SysprofPage *page)
-{
- SysprofDisplay *display;
-
- g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
- g_assert (SYSPROF_IS_PAGE (page));
-
- display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
- sysprof_display_set_visible_page (display, page);
-}
-
-/**
- * sysprof_callgraph_aid_new:
- *
- * Create a new #SysprofCallgraphAid.
- *
- * Returns: (transfer full): a newly created #SysprofCallgraphAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_callgraph_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_CALLGRAPH_AID, NULL);
-}
-
-static void
-sysprof_callgraph_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
- g_assert (SYSPROF_IS_CALLGRAPH_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
-#ifdef __linux__
- {
- const GPid *pids;
- guint n_pids;
-
- if ((pids = sysprof_profiler_get_pids (profiler, &n_pids)))
- {
- for (guint i = 0; i < n_pids; i++)
- {
- g_autoptr(SysprofSource) source = NULL;
-
- source = sysprof_perf_source_new ();
- sysprof_perf_source_set_target_pid (SYSPROF_PERF_SOURCE (source), pids[i]);
- sysprof_profiler_add_source (profiler, source);
- }
- }
- else
- {
- g_autoptr(SysprofSource) source = NULL;
-
- source = sysprof_perf_source_new ();
- sysprof_profiler_add_source (profiler, source);
- }
- }
-#endif
-}
-
-static bool
-discover_samples_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- Present *p = user_data;
-
- g_assert (frame != NULL);
- g_assert (p != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE)
- {
- p->has_samples = TRUE;
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-sysprof_callgraph_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *p = task_data;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_CALLGRAPH_AID (source_object));
- g_assert (p != NULL);
- g_assert (p->cursor != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- /* If we find a sample frame, then we should enable the callgraph
- * and stack visualizers.
- */
- sysprof_capture_cursor_foreach (p->cursor, discover_samples_cb, p);
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_callgraph_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (1, types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_callgraph_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_callgraph_aid_present_worker);
-}
-
-static gboolean
-sysprof_callgraph_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- Present *p;
-
- g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
- g_assert (G_IS_TASK (result));
-
- p = g_task_get_task_data (G_TASK (result));
-
- if (p->has_samples)
- {
- SysprofVisualizerGroup *group;
- SysprofVisualizer *depth;
- SysprofPage *page;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "has-page", TRUE,
- "priority", -500,
- "title", _("Stack Traces"),
- "visible", TRUE,
- NULL);
-
- depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_COMBINED);
- g_object_set (depth,
- "title", _("Stack Traces"),
- "height-request", 35,
- "visible", TRUE,
- NULL);
- sysprof_visualizer_group_insert (group, depth, 0, FALSE);
-
- depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY);
- g_object_set (depth,
- "title", _("Stack Traces (In Kernel)"),
- "height-request", 35,
- "visible", FALSE,
- NULL);
- sysprof_visualizer_group_insert (group, depth, 1, TRUE);
-
- depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_USER_ONLY);
- g_object_set (depth,
- "title", _("Stack Traces (In User)"),
- "height-request", 35,
- "visible", FALSE,
- NULL);
- sysprof_visualizer_group_insert (group, depth, 2, TRUE);
-
- sysprof_display_add_group (p->display, group);
-
- page = g_object_new (SYSPROF_TYPE_CALLGRAPH_PAGE,
- "title", _("Callgraph"),
- "vexpand", TRUE,
- "visible", TRUE,
- NULL);
- sysprof_display_add_page (p->display, page);
- sysprof_display_set_visible_page (p->display, page);
-
- g_signal_connect_object (group,
- "group-activated",
- G_CALLBACK (on_group_activated_cb),
- page,
- 0);
- }
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_callgraph_aid_class_init (SysprofCallgraphAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_callgraph_aid_prepare;
- aid_class->present_async = sysprof_callgraph_aid_present_async;
- aid_class->present_finish = sysprof_callgraph_aid_present_finish;
-}
-
-static void
-sysprof_callgraph_aid_init (SysprofCallgraphAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Callgraph"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-callgraph-page.c b/src/libsysprof-ui/sysprof-callgraph-page.c
deleted file mode 100644
index 0cbabbb4..00000000
--- a/src/libsysprof-ui/sysprof-callgraph-page.c
+++ /dev/null
@@ -1,1299 +0,0 @@
-/* sysprof-callgraph-page.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-/* Sysprof -- Sampling, systemwide CPU profiler
- * Copyright 2004, Red Hat, Inc.
- * Copyright 2004, 2005, 2006, Soeren Sandmann
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include
-
-#include "../stackstash.h"
-
-#include "egg-paned-private.h"
-
-#include "sysprof-callgraph-page.h"
-#include "sysprof-cell-renderer-percent.h"
-
-typedef struct
-{
- SysprofCallgraphProfile *profile;
-
- GtkTreeView *callers_view;
- GtkTreeView *functions_view;
- GtkTreeView *descendants_view;
- GtkTreeViewColumn *descendants_name_column;
- GtkStack *stack;
- GtkWidget *empty_state;
- GtkWidget *loading_state;
- GtkWidget *callgraph;
-
- GQueue *history;
-
- guint profile_size;
- guint loading;
-} SysprofCallgraphPagePrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofCallgraphPage, sysprof_callgraph_page, SYSPROF_TYPE_PAGE)
-
-enum {
- PROP_0,
- PROP_PROFILE,
- N_PROPS
-};
-
-enum {
- GO_PREVIOUS,
- N_SIGNALS
-};
-
-enum {
- COLUMN_NAME,
- COLUMN_SELF,
- COLUMN_TOTAL,
- COLUMN_POINTER,
- COLUMN_HITS,
-};
-
-static void sysprof_callgraph_page_update_descendants (SysprofCallgraphPage *self,
- StackNode *node);
-
-static GParamSpec *properties [N_PROPS];
-static guint signals [N_SIGNALS];
-
-static guint
-sysprof_callgraph_page_get_profile_size (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- StackStash *stash;
- StackNode *node;
- guint size = 0;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- if (priv->profile_size != 0)
- return priv->profile_size;
-
- if (priv->profile == NULL)
- return 0;
-
- if (NULL == (stash = sysprof_callgraph_profile_get_stash (priv->profile)))
- return 0;
-
- for (node = stack_stash_get_root (stash); node != NULL; node = node->siblings)
- size += node->total;
-
- priv->profile_size = size;
-
- return size;
-}
-
-static void
-build_functions_store (StackNode *node,
- gpointer user_data)
-{
- struct {
- GtkListStore *store;
- gdouble profile_size;
- } *state = user_data;
- GtkTreeIter iter;
- const StackNode *n;
- guint size = 0;
- guint total = 0;
-
- g_assert (state != NULL);
- g_assert (GTK_IS_LIST_STORE (state->store));
-
- for (n = node; n != NULL; n = n->next)
- {
- size += n->size;
- if (n->toplevel)
- total += n->total;
- }
-
- gtk_list_store_append (state->store, &iter);
- gtk_list_store_set (state->store, &iter,
- COLUMN_NAME, U64_TO_POINTER(node->data),
- COLUMN_SELF, 100.0 * size / state->profile_size,
- COLUMN_TOTAL, 100.0 * total / state->profile_size,
- COLUMN_POINTER, node,
- -1);
-
-}
-
-static void
-sysprof_callgraph_page_load (SysprofCallgraphPage *self,
- SysprofCallgraphProfile *profile)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkListStore *functions;
- StackStash *stash;
- StackNode *n;
- GtkTreeIter iter;
- struct {
- GtkListStore *store;
- gdouble profile_size;
- } state = { 0 };
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (SYSPROF_IS_CALLGRAPH_PROFILE (profile));
-
- /*
- * TODO: This is probably the type of thing we want to do off the main
- * thread. We should be able to build the tree models off thread
- * and then simply apply them on the main thread.
- *
- * In the mean time, we should set the state of the widget to
- * insensitive and give some indication of loading progress.
- */
-
- if (!g_set_object (&priv->profile, profile))
- return;
-
- if (sysprof_callgraph_profile_is_empty (profile))
- return;
-
- stash = sysprof_callgraph_profile_get_stash (profile);
-
- for (n = stack_stash_get_root (stash); n; n = n->siblings)
- state.profile_size += n->total;
-
- functions = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_POINTER);
-
- state.store = functions;
- stack_stash_foreach_by_address (stash, build_functions_store, &state);
-
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (functions),
- COLUMN_TOTAL,
- GTK_SORT_DESCENDING);
-
- gtk_tree_view_set_model (priv->functions_view, GTK_TREE_MODEL (functions));
- gtk_tree_view_set_model (priv->callers_view, NULL);
- gtk_tree_view_set_model (priv->descendants_view, NULL);
-
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (functions), &iter))
- {
- GtkTreeSelection *selection;
-
- selection = gtk_tree_view_get_selection (priv->functions_view);
- gtk_tree_selection_select_iter (selection, &iter);
- }
-
- gtk_stack_set_visible_child (priv->stack, priv->callgraph);
-
- g_clear_object (&functions);
-}
-
-void
-_sysprof_callgraph_page_set_failed (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- gtk_stack_set_visible_child (priv->stack, priv->empty_state);
-}
-
-static void
-sysprof_callgraph_page_unload (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (SYSPROF_IS_CALLGRAPH_PROFILE (priv->profile));
-
- g_queue_clear (priv->history);
- g_clear_object (&priv->profile);
- priv->profile_size = 0;
-
- gtk_tree_view_set_model (priv->callers_view, NULL);
- gtk_tree_view_set_model (priv->functions_view, NULL);
- gtk_tree_view_set_model (priv->descendants_view, NULL);
-
- gtk_stack_set_visible_child (priv->stack, priv->empty_state);
-}
-
-/**
- * sysprof_callgraph_page_get_profile:
- *
- * Returns: (transfer none): An #SysprofCallgraphProfile.
- */
-SysprofCallgraphProfile *
-sysprof_callgraph_page_get_profile (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (self), NULL);
-
- return priv->profile;
-}
-
-void
-sysprof_callgraph_page_set_profile (SysprofCallgraphPage *self,
- SysprofCallgraphProfile *profile)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_return_if_fail (!profile || SYSPROF_IS_CALLGRAPH_PROFILE (profile));
-
- if (profile != priv->profile)
- {
- if (priv->profile)
- sysprof_callgraph_page_unload (self);
-
- if (profile)
- sysprof_callgraph_page_load (self, profile);
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROFILE]);
- }
-}
-
-static void
-sysprof_callgraph_page_expand_descendants (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeModel *model;
- GList *all_paths = NULL;
- GtkTreePath *first_path;
- GtkTreeIter iter;
- gdouble top_value = 0;
- gint max_rows = 40; /* FIXME */
- gint n_rows;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- model = gtk_tree_view_get_model (priv->descendants_view);
- first_path = gtk_tree_path_new_first ();
- all_paths = g_list_prepend (all_paths, first_path);
- n_rows = 1;
-
- gtk_tree_model_get_iter (model, &iter, first_path);
- gtk_tree_model_get (model, &iter,
- COLUMN_TOTAL, &top_value,
- -1);
-
- while ((all_paths != NULL) && (n_rows < max_rows))
- {
- GtkTreeIter best_iter;
- GtkTreePath *best_path = NULL;
- GList *list;
- gdouble best_value = 0.0;
- gint n_children;
- gint i;
-
- for (list = all_paths; list != NULL; list = list->next)
- {
- GtkTreePath *path = list->data;
-
- g_assert (path != NULL);
-
- if (gtk_tree_model_get_iter (model, &iter, path))
- {
- gdouble value;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_TOTAL, &value,
- -1);
-
- if (value >= best_value)
- {
- best_value = value;
- best_path = path;
- best_iter = iter;
- }
- }
- }
-
- n_children = gtk_tree_model_iter_n_children (model, &best_iter);
-
- if ((n_children > 0) &&
- ((best_value / top_value) > 0.04) &&
- ((n_children + gtk_tree_path_get_depth (best_path)) / (gdouble)max_rows) < (best_value / top_value))
- {
- gtk_tree_view_expand_row (priv->descendants_view, best_path, FALSE);
- n_rows += n_children;
-
- if (gtk_tree_path_get_depth (best_path) < 4)
- {
- GtkTreePath *path;
-
- path = gtk_tree_path_copy (best_path);
- gtk_tree_path_down (path);
-
- for (i = 0; i < n_children; i++)
- {
- all_paths = g_list_prepend (all_paths, path);
-
- path = gtk_tree_path_copy (path);
- gtk_tree_path_next (path);
- }
-
- gtk_tree_path_free (path);
- }
- }
-
- all_paths = g_list_remove (all_paths, best_path);
-
- /* Always expand at least once */
- if ((all_paths == NULL) && (n_rows == 1))
- gtk_tree_view_expand_row (priv->descendants_view, best_path, FALSE);
-
- gtk_tree_path_free (best_path);
- }
-
- g_list_free_full (all_paths, (GDestroyNotify)gtk_tree_path_free);
-}
-
-typedef struct
-{
- StackNode *node;
- const gchar *name;
- guint self;
- guint total;
-} Caller;
-
-static Caller *
-caller_new (StackNode *node)
-{
- Caller *c;
-
- c = g_slice_new (Caller);
- c->name = U64_TO_POINTER (node->data);
- c->self = 0;
- c->total = 0;
- c->node = node;
-
- return c;
-}
-
-static void
-caller_free (gpointer data)
-{
- Caller *c = data;
- g_slice_free (Caller, c);
-}
-
-static void
-sysprof_callgraph_page_function_selection_changed (SysprofCallgraphPage *self,
- GtkTreeSelection *selection)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeModel *model = NULL;
- GtkTreeIter iter;
- GtkListStore *callers_store;
- g_autoptr(GHashTable) callers = NULL;
- g_autoptr(GHashTable) processed = NULL;
- StackNode *callees = NULL;
- StackNode *node;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (GTK_IS_TREE_SELECTION (selection));
-
- if (!gtk_tree_selection_get_selected (selection, &model, &iter))
- {
- gtk_tree_view_set_model (priv->callers_view, NULL);
- gtk_tree_view_set_model (priv->descendants_view, NULL);
- return;
- }
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &callees,
- -1);
-
- sysprof_callgraph_page_update_descendants (self, callees);
-
- callers_store = gtk_list_store_new (4,
- G_TYPE_STRING,
- G_TYPE_DOUBLE,
- G_TYPE_DOUBLE,
- G_TYPE_POINTER);
-
- callers = g_hash_table_new_full (NULL, NULL, NULL, caller_free);
- processed = g_hash_table_new (NULL, NULL);
-
- for (node = callees; node != NULL; node = node->next)
- {
- Caller *c;
-
- if (!node->parent)
- continue;
-
- c = g_hash_table_lookup (callers, U64_TO_POINTER (node->parent->data));
-
- if (c == NULL)
- {
- c = caller_new (node->parent);
- g_hash_table_insert (callers, (gpointer)c->name, c);
- }
- }
-
- for (node = callees; node != NULL; node = node->next)
- {
- StackNode *top_caller = node->parent;
- StackNode *top_callee = node;
- StackNode *n;
- Caller *c;
-
- if (!node->parent)
- continue;
-
- /*
- * We could have a situation where the function was called in a
- * reentrant fashion, so we want to take the top-most match in the
- * stack.
- */
- for (n = node; n && n->parent; n = n->parent)
- {
- if (n->data == node->data && n->parent->data == node->parent->data)
- {
- top_caller = n->parent;
- top_callee = n;
- }
- }
-
- c = g_hash_table_lookup (callers, U64_TO_POINTER (node->parent->data));
-
- g_assert (c != NULL);
-
- if (!g_hash_table_lookup (processed, top_caller))
- {
- c->total += top_callee->total;
- g_hash_table_insert (processed, top_caller, top_caller);
- }
-
- c->self += node->size;
- }
-
- {
- GHashTableIter hiter;
- gpointer key, value;
- guint size = 0;
-
- size = MAX (1, sysprof_callgraph_page_get_profile_size (self));
-
- g_hash_table_iter_init (&hiter, callers);
-
- while (g_hash_table_iter_next (&hiter, &key, &value))
- {
- Caller *c = value;
-
- gtk_list_store_append (callers_store, &iter);
- gtk_list_store_set (callers_store, &iter,
- COLUMN_NAME, c->name,
- COLUMN_SELF, c->self * 100.0 / size,
- COLUMN_TOTAL, c->total * 100.0 / size,
- COLUMN_POINTER, c->node,
- -1);
- }
- }
-
- gtk_tree_view_set_model (priv->callers_view, GTK_TREE_MODEL (callers_store));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (callers_store),
- COLUMN_TOTAL,
- GTK_SORT_DESCENDING);
-
- g_clear_object (&callers_store);
-}
-
-static void
-sysprof_callgraph_page_set_node (SysprofCallgraphPage *self,
- StackNode *node)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (node != NULL);
-
- if (priv->profile == NULL)
- return;
-
- model = gtk_tree_view_get_model (priv->functions_view);
-
- if (gtk_tree_model_get_iter_first (model, &iter))
- {
- do
- {
- StackNode *item = NULL;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &item,
- -1);
-
- if (item != NULL && item->data == node->data)
- {
- GtkTreeSelection *selection;
-
- selection = gtk_tree_view_get_selection (priv->functions_view);
- gtk_tree_selection_select_iter (selection, &iter);
-
- break;
- }
- }
- while (gtk_tree_model_iter_next (model, &iter));
- }
-}
-
-static void
-sysprof_callgraph_page_descendant_activated (SysprofCallgraphPage *self,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- GtkTreeView *tree_view)
-{
- GtkTreeModel *model;
- StackNode *node = NULL;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (GTK_IS_TREE_VIEW (tree_view));
- g_assert (path != NULL);
- g_assert (GTK_IS_TREE_VIEW_COLUMN (column));
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (!gtk_tree_model_get_iter (model, &iter, path))
- return;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &node,
- -1);
-
- if (node != NULL)
- sysprof_callgraph_page_set_node (self, node);
-}
-
-static void
-sysprof_callgraph_page_caller_activated (SysprofCallgraphPage *self,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- GtkTreeView *tree_view)
-{
- GtkTreeModel *model;
- StackNode *node = NULL;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (GTK_IS_TREE_VIEW (tree_view));
- g_assert (path != NULL);
- g_assert (GTK_IS_TREE_VIEW_COLUMN (column));
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (!gtk_tree_model_get_iter (model, &iter, path))
- return;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &node,
- -1);
-
- if (node != NULL)
- sysprof_callgraph_page_set_node (self, node);
-}
-
-static void
-sysprof_callgraph_page_tag_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- SysprofCallgraphPage *self = data;
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- StackNode *node = NULL;
- const gchar *str = NULL;
-
- if (priv->profile == NULL)
- return;
-
- gtk_tree_model_get (model, iter, COLUMN_POINTER, &node, -1);
-
- if (node && node->data)
- {
- GQuark tag;
-
- tag = sysprof_callgraph_profile_get_tag (priv->profile, GSIZE_TO_POINTER (node->data));
- if (tag != 0)
- str = g_quark_to_string (tag);
- }
-
- g_object_set (cell, "text", str, NULL);
-}
-
-static void
-sysprof_callgraph_page_real_go_previous (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- StackNode *node;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- node = g_queue_pop_head (priv->history);
-
- if (NULL != (node = g_queue_peek_head (priv->history)))
- sysprof_callgraph_page_set_node (self, node);
-}
-
-static gboolean
-descendants_view_move_cursor_cb (GtkTreeView *descendants_view,
- GtkMovementStep step,
- int direction,
- gboolean extend,
- gboolean modify,
- gpointer user_data)
-{
- if (step == GTK_MOVEMENT_VISUAL_POSITIONS)
- {
- GtkTreePath *path;
-
- gtk_tree_view_get_cursor (descendants_view, &path, NULL);
-
- if (direction == 1)
- {
- gtk_tree_view_expand_row (descendants_view, path, FALSE);
- g_signal_stop_emission_by_name (descendants_view, "move-cursor");
- return FALSE;
- }
- else if (direction == -1)
- {
- gtk_tree_view_collapse_row (descendants_view, path);
- g_signal_stop_emission_by_name (descendants_view, "move-cursor");
- return FALSE;
- }
-
- gtk_tree_path_free (path);
- }
-
- return TRUE;
-}
-
-static void
-copy_tree_view_selection_cb (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- g_autofree gchar *name = NULL;
- gchar sstr[16];
- gchar tstr[16];
- GString *str = data;
- gdouble self;
- gdouble total;
- gint depth;
-
- g_assert (GTK_IS_TREE_MODEL (model));
- g_assert (path != NULL);
- g_assert (iter != NULL);
- g_assert (str != NULL);
-
- depth = gtk_tree_path_get_depth (path);
- gtk_tree_model_get (model, iter,
- COLUMN_NAME, &name,
- COLUMN_SELF, &self,
- COLUMN_TOTAL, &total,
- -1);
-
- g_snprintf (sstr, sizeof sstr, "%.2lf%%", self);
- g_snprintf (tstr, sizeof tstr, "%.2lf%%", total);
-
- g_string_append_printf (str, "[%8s] [%8s] ", sstr, tstr);
-
- for (gint i = 1; i < depth; i++)
- g_string_append (str, " ");
- g_string_append (str, name);
- g_string_append_c (str, '\n');
-}
-
-static void
-copy_tree_view_selection (GtkTreeView *tree_view)
-{
- g_autoptr(GString) str = NULL;
- GdkClipboard *clipboard;
-
- g_assert (GTK_IS_TREE_VIEW (tree_view));
-
- str = g_string_new (" SELF TOTAL FUNCTION\n");
- gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree_view),
- copy_tree_view_selection_cb,
- str);
-
- clipboard = gtk_widget_get_clipboard (GTK_WIDGET (tree_view));
- gdk_clipboard_set_text (clipboard, str->str);
-}
-
-static void
-sysprof_callgraph_page_copy_cb (GtkWidget *widget,
- const char *action_name,
- GVariant *param)
-{
- SysprofCallgraphPage *self = (SysprofCallgraphPage *)widget;
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkRoot *toplevel;
- GtkWidget *focus;
-
- g_assert (GTK_IS_WIDGET (widget));
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- if (!(toplevel = gtk_widget_get_root (widget)) ||
- !GTK_IS_ROOT (toplevel) ||
- !(focus = gtk_root_get_focus (toplevel)))
- return;
-
- if (focus == GTK_WIDGET (priv->descendants_view))
- copy_tree_view_selection (priv->descendants_view);
- else if (focus == GTK_WIDGET (priv->callers_view))
- copy_tree_view_selection (priv->callers_view);
- else if (focus == GTK_WIDGET (priv->functions_view))
- copy_tree_view_selection (priv->functions_view);
-}
-
-static void
-sysprof_callgraph_page_generate_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofProfile *profile = (SysprofProfile *)object;
- SysprofCallgraphPage *self;
- g_autoptr(GTask) task = user_data;
- g_autoptr(GError) error = NULL;
-
- g_assert (SYSPROF_IS_PROFILE (profile));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- self = g_task_get_source_object (task);
-
- if (!sysprof_profile_generate_finish (profile, result, &error))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- sysprof_callgraph_page_set_profile (self, SYSPROF_CALLGRAPH_PROFILE (profile));
-}
-
-static void
-sysprof_callgraph_page_load_async (SysprofPage *page,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *filter,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SysprofCallgraphPage *self = (SysprofCallgraphPage *)page;
- g_autoptr(SysprofCaptureReader) copy = NULL;
- g_autoptr(SysprofProfile) profile = NULL;
- g_autoptr(GTask) task = NULL;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_SELECTION (selection));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_callgraph_page_load_async);
-
- copy = sysprof_capture_reader_copy (reader);
-
- profile = sysprof_callgraph_profile_new_with_selection (selection);
- sysprof_profile_set_reader (profile, reader);
- sysprof_profile_generate (profile,
- cancellable,
- sysprof_callgraph_page_generate_cb,
- g_steal_pointer (&task));
-}
-
-static gboolean
-sysprof_callgraph_page_load_finish (SysprofPage *page,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (page), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_callgraph_page_finalize (GObject *object)
-{
- SysprofCallgraphPage *self = (SysprofCallgraphPage *)object;
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- g_clear_pointer (&priv->history, g_queue_free);
- g_clear_object (&priv->profile);
-
- G_OBJECT_CLASS (sysprof_callgraph_page_parent_class)->finalize (object);
-}
-
-static void
-sysprof_callgraph_page_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofCallgraphPage *self = SYSPROF_CALLGRAPH_PAGE (object);
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_PROFILE:
- g_value_set_object (value, priv->profile);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_callgraph_page_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofCallgraphPage *self = SYSPROF_CALLGRAPH_PAGE (object);
-
- switch (prop_id)
- {
- case PROP_PROFILE:
- sysprof_callgraph_page_set_profile (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_callgraph_page_class_init (SysprofCallgraphPageClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
-
- object_class->finalize = sysprof_callgraph_page_finalize;
- object_class->get_property = sysprof_callgraph_page_get_property;
- object_class->set_property = sysprof_callgraph_page_set_property;
-
- page_class->load_async = sysprof_callgraph_page_load_async;
- page_class->load_finish = sysprof_callgraph_page_load_finish;
-
- klass->go_previous = sysprof_callgraph_page_real_go_previous;
-
- properties [PROP_PROFILE] =
- g_param_spec_object ("profile",
- "Profile",
- "The callgraph profile to view",
- SYSPROF_TYPE_CALLGRAPH_PROFILE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- signals [GO_PREVIOUS] =
- g_signal_new ("go-previous",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (SysprofCallgraphPageClass, go_previous),
- NULL, NULL, NULL, G_TYPE_NONE, 0);
-
- gtk_widget_class_set_template_from_resource (widget_class,
- "/org/gnome/sysprof/ui/sysprof-callgraph-page.ui");
-
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, callers_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, functions_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, descendants_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, descendants_name_column);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, stack);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, callgraph);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, empty_state);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofCallgraphPage, loading_state);
-
- gtk_widget_class_install_action (widget_class, "page.copy", NULL, sysprof_callgraph_page_copy_cb);
-
- gtk_widget_class_add_binding_action (widget_class, GDK_KEY_c, GDK_CONTROL_MASK, "page.copy", NULL);
- gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Left, GDK_ALT_MASK, "go-previous", NULL);
-
- g_type_ensure (EGG_TYPE_PANED);
- g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_PERCENT);
-}
-
-static void
-sysprof_callgraph_page_init (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeSelection *selection;
- GtkCellRenderer *cell;
-
- priv->history = g_queue_new ();
-
- gtk_widget_init_template (GTK_WIDGET (self));
-
- gtk_stack_set_visible_child (priv->stack, priv->loading_state);
-
- selection = gtk_tree_view_get_selection (priv->functions_view);
-
- g_signal_connect_object (selection,
- "changed",
- G_CALLBACK (sysprof_callgraph_page_function_selection_changed),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->descendants_view,
- "row-activated",
- G_CALLBACK (sysprof_callgraph_page_descendant_activated),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->callers_view,
- "row-activated",
- G_CALLBACK (sysprof_callgraph_page_caller_activated),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect (priv->descendants_view,
- "move-cursor",
- G_CALLBACK (descendants_view_move_cursor_cb),
- NULL);
-
- cell = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
- "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
- "xalign", 0.0f,
- NULL);
- gtk_tree_view_column_pack_start (priv->descendants_name_column, cell, TRUE);
- gtk_tree_view_column_add_attribute (priv->descendants_name_column, cell, "text", 0);
-
- cell = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
- "foreground", "#666666",
- "scale", PANGO_SCALE_SMALL,
- "xalign", 1.0f,
- NULL);
- gtk_tree_view_column_pack_start (priv->descendants_name_column, cell, FALSE);
- gtk_tree_view_column_set_cell_data_func (priv->descendants_name_column, cell,
- sysprof_callgraph_page_tag_data_func,
- self, NULL);
-
- gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->descendants_view),
- GTK_SELECTION_MULTIPLE);
-}
-
-typedef struct _Descendant Descendant;
-
-struct _Descendant
-{
- const gchar *name;
- guint self;
- guint cumulative;
- Descendant *parent;
- Descendant *siblings;
- Descendant *children;
-};
-
-static void
-build_tree_cb (StackLink *trace,
- gint size,
- gpointer user_data)
-{
- Descendant **tree = user_data;
- Descendant *parent = NULL;
- StackLink *link;
-
- g_assert (trace != NULL);
- g_assert (tree != NULL);
-
- /* Get last item */
- link = trace;
- while (link->next)
- link = link->next;
-
- for (; link != NULL; link = link->prev)
- {
- const gchar *address = U64_TO_POINTER (link->data);
- Descendant *prev = NULL;
- Descendant *match = NULL;
-
- for (match = *tree; match != NULL; match = match->siblings)
- {
- if (match->name == address)
- {
- if (prev != NULL)
- {
- /* Move to front */
- prev->siblings = match->siblings;
- match->siblings = *tree;
- *tree = match;
- }
- break;
- }
- }
-
- if (match == NULL)
- {
- /* Have we seen this object further up the tree? */
- for (match = parent; match != NULL; match = match->parent)
- {
- if (match->name == address)
- break;
- }
- }
-
- if (match == NULL)
- {
- match = g_slice_new (Descendant);
- match->name = address;
- match->cumulative = 0;
- match->self = 0;
- match->children = NULL;
- match->parent = parent;
- match->siblings = *tree;
- *tree = match;
- }
-
- tree = &match->children;
- parent = match;
- }
-
- parent->self += size;
-
- for (; parent != NULL; parent = parent->parent)
- parent->cumulative += size;
-}
-
-static Descendant *
-build_tree (StackNode *node)
-{
- Descendant *tree = NULL;
-
- for (; node != NULL; node = node->next)
- {
- if (node->toplevel)
- stack_node_foreach_trace (node, build_tree_cb, &tree);
- }
-
- return tree;
-}
-
-static void
-append_to_tree_and_free (SysprofCallgraphPage *self,
- StackStash *stash,
- GtkTreeStore *store,
- Descendant *item,
- GtkTreeIter *parent)
-{
- StackNode *node = NULL;
- GtkTreeIter iter;
- guint profile_size;
-
- g_assert (GTK_IS_TREE_STORE (store));
- g_assert (item != NULL);
-
- profile_size = MAX (1, sysprof_callgraph_page_get_profile_size (self));
-
- gtk_tree_store_append (store, &iter, parent);
-
- node = stack_stash_find_node (stash, (gpointer)item->name);
-
- gtk_tree_store_set (store, &iter,
- COLUMN_NAME, item->name,
- COLUMN_SELF, item->self * 100.0 / (gdouble)profile_size,
- COLUMN_TOTAL, item->cumulative * 100.0 / (gdouble)profile_size,
- COLUMN_POINTER, node,
- COLUMN_HITS, (guint)item->cumulative,
- -1);
-
- if (item->siblings != NULL)
- append_to_tree_and_free (self, stash, store, item->siblings, parent);
-
- if (item->children != NULL)
- append_to_tree_and_free (self, stash, store, item->children, &iter);
-
- g_slice_free (Descendant, item);
-}
-
-static void
-sysprof_callgraph_page_update_descendants (SysprofCallgraphPage *self,
- StackNode *node)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeStore *store;
-
- g_assert (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- if (g_queue_peek_head (priv->history) != node)
- g_queue_push_head (priv->history, node);
-
- store = gtk_tree_store_new (5,
- G_TYPE_STRING,
- G_TYPE_DOUBLE,
- G_TYPE_DOUBLE,
- G_TYPE_POINTER,
- G_TYPE_UINT);
-
- if (priv->profile != NULL)
- {
- StackStash *stash;
-
- stash = sysprof_callgraph_profile_get_stash (priv->profile);
- if (stash != NULL)
- {
- Descendant *tree;
-
- tree = build_tree (node);
- if (tree != NULL)
- append_to_tree_and_free (self, stash, store, tree, NULL);
- }
- }
-
- gtk_tree_view_set_model (priv->descendants_view, GTK_TREE_MODEL (store));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
- COLUMN_TOTAL, GTK_SORT_DESCENDING);
- sysprof_callgraph_page_expand_descendants (self);
-
- g_clear_object (&store);
-}
-
-/**
- * sysprof_callgraph_page_screenshot:
- * @self: A #SysprofCallgraphPage.
- *
- * This function will generate a text representation of the descendants tree.
- * This is useful if you want to include various profiling information in a
- * commit message or email.
- *
- * The text generated will match the current row expansion in the tree view.
- *
- * Returns: (nullable) (transfer full): A newly allocated string that should be freed
- * with g_free().
- */
-gchar *
-sysprof_callgraph_page_screenshot (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeView *tree_view;
- GtkTreeModel *model;
- GtkTreePath *tree_path;
- GString *str;
- GtkTreeIter iter;
-
- g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (self), NULL);
-
- tree_view = priv->descendants_view;
-
- if (NULL == (model = gtk_tree_view_get_model (tree_view)))
- return NULL;
-
- /*
- * To avoid having to precalculate the deepest visible row, we
- * put the timing information at the beginning of the line.
- */
-
- str = g_string_new (" SELF CUMULATIVE FUNCTION\n");
- tree_path = gtk_tree_path_new_first ();
-
- for (;;)
- {
- if (gtk_tree_model_get_iter (model, &iter, tree_path))
- {
- guint depth = gtk_tree_path_get_depth (tree_path);
- StackNode *node;
- gdouble in_self;
- gdouble total;
- guint i;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_SELF, &in_self,
- COLUMN_TOTAL, &total,
- COLUMN_POINTER, &node,
- -1);
-
- g_string_append_printf (str, "[% 7.2lf%%] [% 7.2lf%%] ", in_self, total);
-
- for (i = 0; i < depth; i++)
- g_string_append (str, " ");
- g_string_append (str, GSIZE_TO_POINTER (node->data));
- g_string_append_c (str, '\n');
-
- if (gtk_tree_view_row_expanded (tree_view, tree_path))
- gtk_tree_path_down (tree_path);
- else
- gtk_tree_path_next (tree_path);
-
- continue;
- }
-
- if (!gtk_tree_path_up (tree_path) || !gtk_tree_path_get_depth (tree_path))
- break;
-
- gtk_tree_path_next (tree_path);
- }
-
- gtk_tree_path_free (tree_path);
-
- return g_string_free (str, FALSE);
-}
-
-guint
-sysprof_callgraph_page_get_n_functions (SysprofCallgraphPage *self)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
- GtkTreeModel *model;
- guint ret = 0;
-
- g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (self), 0);
-
- if (NULL != (model = gtk_tree_view_get_model (priv->functions_view)))
- ret = gtk_tree_model_iter_n_children (model, NULL);
-
- return ret;
-}
-
-void
-_sysprof_callgraph_page_set_loading (SysprofCallgraphPage *self,
- gboolean loading)
-{
- SysprofCallgraphPagePrivate *priv = sysprof_callgraph_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_CALLGRAPH_PAGE (self));
-
- if (loading)
- priv->loading++;
- else
- priv->loading--;
-
- if (priv->loading)
- gtk_stack_set_visible_child (priv->stack, priv->loading_state);
- else
- gtk_stack_set_visible_child (priv->stack, priv->callgraph);
-}
diff --git a/src/libsysprof-ui/sysprof-callgraph-page.h b/src/libsysprof-ui/sysprof-callgraph-page.h
deleted file mode 100644
index 7624c580..00000000
--- a/src/libsysprof-ui/sysprof-callgraph-page.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* sysprof-callgraph-page.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-#include
-
-#include "sysprof-page.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_CALLGRAPH_PAGE (sysprof_callgraph_page_get_type())
-
-G_DECLARE_DERIVABLE_TYPE (SysprofCallgraphPage, sysprof_callgraph_page, SYSPROF, CALLGRAPH_PAGE, SysprofPage)
-
-struct _SysprofCallgraphPageClass
-{
- SysprofPageClass parent_class;
-
- void (*go_previous) (SysprofCallgraphPage *self);
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-GtkWidget *sysprof_callgraph_page_new (void);
-SysprofCallgraphProfile *sysprof_callgraph_page_get_profile (SysprofCallgraphPage *self);
-void sysprof_callgraph_page_set_profile (SysprofCallgraphPage *self,
- SysprofCallgraphProfile *profile);
-gchar *sysprof_callgraph_page_screenshot (SysprofCallgraphPage *self);
-guint sysprof_callgraph_page_get_n_functions (SysprofCallgraphPage *self);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-callgraph-page.ui b/src/libsysprof-ui/sysprof-callgraph-page.ui
deleted file mode 100644
index b0dc4f26..00000000
--- a/src/libsysprof-ui/sysprof-callgraph-page.ui
+++ /dev/null
@@ -1,212 +0,0 @@
-
-
-
-
-
-
- horizontal
-
-
- vertical
- 400
-
-
- true
-
-
- true
-
-
- true
- fixed
- 0
- Functions
-
-
- middle
-
-
- 0
-
-
-
-
-
-
- false
- fixed
- 1
- Self
-
-
- 65
-
-
- 1
-
-
-
-
-
-
- false
- fixed
- 2
- Total
-
-
- 65
-
-
- 2
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
- true
- fixed
- 0
- Callers
-
-
- middle
-
-
- 0
-
-
-
-
-
-
- false
- fixed
- 1
- Self
-
-
- 65
-
-
- 1
-
-
-
-
-
-
- false
- fixed
- 2
- Total
-
-
- 65
-
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
- true
- autosize
- 0
- Descendants
-
-
-
-
- false
- fixed
- 1
- Self
-
-
- 65
-
-
- 1
-
-
-
-
-
-
- false
- fixed
- 2
- Total
-
-
- 65
-
-
- 2
-
-
-
-
-
-
- false
- fixed
- Hits
-
-
- 1.0
-
-
- 4
-
-
-
-
-
-
-
-
-
-
-
-
- content-loading-symbolic
- Generating Callgraph
- Sysprof is busy creating the selected callgraph.
-
-
-
-
- computer-fail-symbolic
- Not Enough Samples
- More samples are necessary to display a callgraph.
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-cell-renderer-duration.c b/src/libsysprof-ui/sysprof-cell-renderer-duration.c
deleted file mode 100644
index 3e60166e..00000000
--- a/src/libsysprof-ui/sysprof-cell-renderer-duration.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/* sysprof-cell-renderer-duration.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-cell-renderer-duration"
-
-#include "config.h"
-
-#include "sysprof-cell-renderer-duration.h"
-#include "sysprof-ui-private.h"
-#include "sysprof-zoom-manager.h"
-
-typedef struct
-{
- gint64 capture_begin_time;
- gint64 capture_end_time;
- gint64 capture_duration;
- gint64 begin_time;
- gint64 end_time;
- gchar *text;
- SysprofZoomManager *zoom_manager;
- GdkRGBA color;
- guint color_set : 1;
-} SysprofCellRendererDurationPrivate;
-
-enum {
- PROP_0,
- PROP_BEGIN_TIME,
- PROP_CAPTURE_BEGIN_TIME,
- PROP_CAPTURE_END_TIME,
- PROP_COLOR,
- PROP_END_TIME,
- PROP_TEXT,
- PROP_ZOOM_MANAGER,
- N_PROPS
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererDuration, sysprof_cell_renderer_duration, GTK_TYPE_CELL_RENDERER)
-
-static GParamSpec *properties [N_PROPS];
-
-static inline void
-rounded_rectangle (cairo_t *cr,
- const GdkRectangle *rect,
- int x_radius,
- int y_radius)
-{
- int x;
- int y;
- int width;
- int height;
- int x1, x2;
- int y1, y2;
- int xr1, xr2;
- int yr1, yr2;
-
- g_assert (cr);
- g_assert (rect);
-
- x = rect->x;
- y = rect->y;
- width = rect->width;
- height = rect->height;
-
- x1 = x;
- x2 = x1 + width;
- y1 = y;
- y2 = y1 + height;
-
- x_radius = MIN (x_radius, width / 2.0);
- y_radius = MIN (y_radius, width / 2.0);
-
- xr1 = x_radius;
- xr2 = x_radius / 2.0;
- yr1 = y_radius;
- yr2 = y_radius / 2.0;
-
- cairo_move_to (cr, x1 + xr1, y1);
- cairo_line_to (cr, x2 - xr1, y1);
- cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
- cairo_line_to (cr, x2, y2 - yr1);
- cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
- cairo_line_to (cr, x1 + xr1, y2);
- cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
- cairo_line_to (cr, x1, y1 + yr1);
- cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
- cairo_close_path (cr);
-}
-
-static void
-sysprof_cell_renderer_duration_snapshot (GtkCellRenderer *renderer,
- GtkSnapshot *snapshot,
- GtkWidget *widget,
- const GdkRectangle *bg_area,
- const GdkRectangle *cell_area,
- GtkCellRendererState state)
-{
- SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)renderer;
- SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
- g_autoptr(GString) str = NULL;
- GtkStyleContext *style_context;
- cairo_t *cr;
- gdouble x1, x2;
- GdkRGBA rgba;
- GdkRectangle r;
- gint64 duration;
-
- g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self));
- g_assert (snapshot != NULL);
- g_assert (GTK_IS_WIDGET (widget));
-
- if (priv->zoom_manager == NULL)
- return;
-
- cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (cell_area->x, cell_area->y, cell_area->width, cell_area->height));
-
- style_context = gtk_widget_get_style_context (widget);
-
- if (priv->color_set)
- rgba = priv->color;
- else
- gtk_style_context_get_color (style_context, &rgba);
-
- duration = sysprof_zoom_manager_get_duration_for_width (priv->zoom_manager, bg_area->width);
-
- x1 = (priv->begin_time - priv->capture_begin_time) / (gdouble)duration * cell_area->width;
- x2 = (priv->end_time - priv->capture_begin_time) / (gdouble)duration * cell_area->width;
-
- if (x2 < x1)
- x2 = x1;
-
- r.x = cell_area->x + x1;
- r.height = 12;
- r.y = cell_area->y + (cell_area->height - r.height) / 2;
- r.width = MAX (1.0, x2 - x1);
-
- if ((cell_area->height - r.height) % 2 == 1)
- r.height++;
-
- gdk_cairo_set_source_rgba (cr, &rgba);
-
- if (r.width > 3)
- {
- rounded_rectangle (cr, &r, 2, 2);
- cairo_fill (cr);
- }
- else if (r.width > 1)
- {
- gdk_cairo_rectangle (cr, &r);
- cairo_fill (cr);
- }
- else
- {
- cairo_set_line_width (cr, 1);
- cairo_move_to (cr, r.x + .5, r.y);
- cairo_line_to (cr, r.x + .5, r.y + r.height);
- cairo_stroke (cr);
- }
-
- str = g_string_new (NULL);
-
- if (priv->begin_time != priv->end_time)
- {
- g_autofree gchar *fmt = _sysprof_format_duration (priv->end_time - priv->begin_time);
- g_string_append_printf (str, "%s — ", fmt);
- }
-
- if (priv->text != NULL)
- g_string_append (str, priv->text);
-
- if (str->len)
- {
- PangoLayout *layout;
- gint w, h;
-
- /* Add some spacing before/after */
- r.x -= 24;
- r.width += 48;
-
- layout = gtk_widget_create_pango_layout (widget, NULL);
- pango_layout_set_text (layout, str->str, str->len);
- pango_layout_get_pixel_size (layout, &w, &h);
-
- if ((r.x + r.width + w) < (cell_area->x + cell_area->width) ||
- ((cell_area->x + w) > r.x))
- cairo_move_to (cr, r.x + r.width, r.y + ((r.height - h) / 2));
- else
- cairo_move_to (cr, r.x - w, r.y + ((r.height - h) / 2));
-
- if (priv->end_time < priv->begin_time)
- {
- gdk_rgba_parse (&rgba, "#f00");
- if (state & GTK_CELL_RENDERER_SELECTED)
- rgba.alpha = 0.6;
- }
-
- gdk_cairo_set_source_rgba (cr, &rgba);
- pango_cairo_show_layout (cr, layout);
-
- g_object_unref (layout);
- }
-
- cairo_destroy (cr);
-}
-
-static GtkSizeRequestMode
-sysprof_cell_renderer_duration_get_request_mode (GtkCellRenderer *renderer)
-{
- return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
-}
-
-static void
-sysprof_cell_renderer_duration_get_preferred_width (GtkCellRenderer *cell,
- GtkWidget *widget,
- gint *min_width,
- gint *nat_width)
-{
- SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)cell;
- SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
- gint width = 1;
-
- g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self));
- g_assert (GTK_IS_WIDGET (widget));
-
- GTK_CELL_RENDERER_CLASS (sysprof_cell_renderer_duration_parent_class)->get_preferred_width (cell, widget, min_width, nat_width);
-
- if (priv->zoom_manager && priv->capture_begin_time && priv->capture_end_time)
- width = sysprof_zoom_manager_get_width_for_duration (priv->zoom_manager,
- priv->capture_end_time - priv->capture_begin_time);
-
- if (min_width)
- *min_width = width;
-
- if (nat_width)
- *nat_width = width;
-}
-
-static void
-sysprof_cell_renderer_duration_get_preferred_height_for_width (GtkCellRenderer *cell,
- GtkWidget *widget,
- gint width,
- gint *min_height,
- gint *nat_height)
-{
- PangoLayout *layout;
- gint w, h;
- gint ypad;
-
- g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (cell));
-
- gtk_cell_renderer_get_padding (cell, NULL, &ypad);
-
- layout = gtk_widget_create_pango_layout (widget, "XMZ09");
- pango_layout_get_pixel_size (layout, &w, &h);
- g_clear_object (&layout);
-
- if (min_height)
- *min_height = h + (ypad * 2);
-
- if (nat_height)
- *nat_height = h + (ypad * 2);
-}
-
-static void
-sysprof_cell_renderer_duration_finalize (GObject *object)
-{
- SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)object;
- SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
-
- g_clear_object (&priv->zoom_manager);
- g_clear_pointer (&priv->text, g_free);
-
- G_OBJECT_CLASS (sysprof_cell_renderer_duration_parent_class)->finalize (object);
-}
-
-static void
-sysprof_cell_renderer_duration_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object);
- SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_BEGIN_TIME:
- g_value_set_int64 (value, priv->begin_time);
- break;
-
- case PROP_CAPTURE_BEGIN_TIME:
- g_value_set_int64 (value, priv->capture_begin_time);
- break;
-
- case PROP_CAPTURE_END_TIME:
- g_value_set_int64 (value, priv->capture_end_time);
- break;
-
- case PROP_END_TIME:
- g_value_set_int64 (value, priv->end_time);
- break;
-
- case PROP_TEXT:
- g_value_set_string (value, priv->text);
- break;
-
- case PROP_ZOOM_MANAGER:
- g_value_set_object (value, priv->zoom_manager);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_cell_renderer_duration_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object);
- SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_BEGIN_TIME:
- priv->begin_time = g_value_get_int64 (value);
- break;
-
- case PROP_CAPTURE_BEGIN_TIME:
- priv->capture_begin_time = g_value_get_int64 (value);
- priv->capture_duration = priv->capture_end_time - priv->capture_begin_time;
- break;
-
- case PROP_CAPTURE_END_TIME:
- priv->capture_end_time = g_value_get_int64 (value);
- priv->capture_duration = priv->capture_end_time - priv->capture_begin_time;
- break;
-
- case PROP_COLOR:
- if (g_value_get_boxed (value))
- priv->color = *(GdkRGBA *)g_value_get_boxed (value);
- else
- gdk_rgba_parse (&priv->color, "#000");
- priv->color_set = !!g_value_get_boolean (value);
- break;
-
- case PROP_END_TIME:
- priv->end_time = g_value_get_int64 (value);
- break;
-
- case PROP_TEXT:
- g_free (priv->text);
- priv->text = g_value_dup_string (value);
- break;
-
- case PROP_ZOOM_MANAGER:
- g_set_object (&priv->zoom_manager, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_cell_renderer_duration_class_init (SysprofCellRendererDurationClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
-
- object_class->finalize = sysprof_cell_renderer_duration_finalize;
- object_class->get_property = sysprof_cell_renderer_duration_get_property;
- object_class->set_property = sysprof_cell_renderer_duration_set_property;
-
- cell_class->get_preferred_height_for_width = sysprof_cell_renderer_duration_get_preferred_height_for_width;
- cell_class->get_preferred_width = sysprof_cell_renderer_duration_get_preferred_width;
- cell_class->get_request_mode = sysprof_cell_renderer_duration_get_request_mode;
- cell_class->snapshot = sysprof_cell_renderer_duration_snapshot;
-
- /* Note we do not emit ::notify() for these properties */
-
- properties [PROP_BEGIN_TIME] =
- g_param_spec_int64 ("begin-time", NULL, NULL,
- G_MININT64, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CAPTURE_BEGIN_TIME] =
- g_param_spec_int64 ("capture-begin-time", NULL, NULL,
- G_MININT64, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CAPTURE_END_TIME] =
- g_param_spec_int64 ("capture-end-time", NULL, NULL,
- G_MININT64, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_COLOR] =
- g_param_spec_boxed ("color", NULL, NULL,
- GDK_TYPE_RGBA,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_END_TIME] =
- g_param_spec_int64 ("end-time", NULL, NULL,
- G_MININT64, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_END_TIME] =
- g_param_spec_int64 ("end-time", NULL, NULL,
- G_MININT64, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_TEXT] =
- g_param_spec_string ("text", NULL, NULL,
- NULL,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_ZOOM_MANAGER] =
- g_param_spec_object ("zoom-manager", NULL, NULL,
- SYSPROF_TYPE_ZOOM_MANAGER,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-sysprof_cell_renderer_duration_init (SysprofCellRendererDuration *self)
-{
- SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
-
- priv->color.alpha = 1.0;
-}
-
-GtkCellRenderer *
-sysprof_cell_renderer_duration_new (void)
-{
- return g_object_new (SYSPROF_TYPE_CELL_RENDERER_DURATION, NULL);
-}
diff --git a/src/libsysprof-ui/sysprof-cell-renderer-percent.c b/src/libsysprof-ui/sysprof-cell-renderer-percent.c
deleted file mode 100644
index e23e1fed..00000000
--- a/src/libsysprof-ui/sysprof-cell-renderer-percent.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* sysprof-cell-renderer-percent.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-cell-renderer-percent"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-cell-renderer-percent.h"
-
-typedef struct
-{
- gdouble percent;
-} SysprofCellRendererPercentPrivate;
-
-enum {
- PROP_0,
- PROP_PERCENT,
- N_PROPS
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererPercent, sysprof_cell_renderer_percent, SYSPROF_TYPE_CELL_RENDERER_PROGRESS)
-
-static GParamSpec *properties [N_PROPS];
-
-static void
-sysprof_cell_renderer_percent_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofCellRendererPercent *self = SYSPROF_CELL_RENDERER_PERCENT (object);
-
- switch (prop_id)
- {
- case PROP_PERCENT:
- g_value_set_double (value, sysprof_cell_renderer_percent_get_percent (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_cell_renderer_percent_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofCellRendererPercent *self = SYSPROF_CELL_RENDERER_PERCENT (object);
-
- switch (prop_id)
- {
- case PROP_PERCENT:
- sysprof_cell_renderer_percent_set_percent (self, g_value_get_double (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_cell_renderer_percent_class_init (SysprofCellRendererPercentClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->get_property = sysprof_cell_renderer_percent_get_property;
- object_class->set_property = sysprof_cell_renderer_percent_set_property;
-
- properties [PROP_PERCENT] =
- g_param_spec_double ("percent",
- "Percent",
- "Percent",
- 0.0,
- 100.0,
- 0.0,
- /* Doesn't notify to avoid signal emission */
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-sysprof_cell_renderer_percent_init (SysprofCellRendererPercent *self)
-{
- g_object_set (self, "text-xalign", 1.0f, NULL);
-}
-
-gdouble
-sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self)
-{
- SysprofCellRendererPercentPrivate *priv = sysprof_cell_renderer_percent_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_CELL_RENDERER_PERCENT (self), 0.0);
-
- return priv->percent;
-}
-
-void
-sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
- gdouble percent)
-{
- SysprofCellRendererPercentPrivate *priv = sysprof_cell_renderer_percent_get_instance_private (self);
- gchar text[8];
-
- g_return_if_fail (SYSPROF_IS_CELL_RENDERER_PERCENT (self));
- g_return_if_fail (percent >= 0.0);
- g_return_if_fail (percent <= 100.0);
-
- priv->percent = percent;
-
- g_snprintf (text, sizeof text, "%.2lf%%", percent);
- text [sizeof text - 1] = '\0';
-
- g_object_set (self,
- "value", (guint)percent,
- "text", text,
- NULL);
-}
diff --git a/src/libsysprof-ui/sysprof-cell-renderer-percent.h b/src/libsysprof-ui/sysprof-cell-renderer-percent.h
deleted file mode 100644
index 44a8fc04..00000000
--- a/src/libsysprof-ui/sysprof-cell-renderer-percent.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* sysprof-cell-renderer-percent.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-cell-renderer-progress.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_CELL_RENDERER_PERCENT (sysprof_cell_renderer_percent_get_type())
-#define SYSPROF_CELL_RENDERER_PERCENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercent))
-#define SYSPROF_CELL_RENDERER_PERCENT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercent const))
-#define SYSPROF_CELL_RENDERER_PERCENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercentClass))
-#define SYSPROF_IS_CELL_RENDERER_PERCENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT))
-#define SYSPROF_IS_CELL_RENDERER_PERCENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SYSPROF_TYPE_CELL_RENDERER_PERCENT))
-#define SYSPROF_CELL_RENDERER_PERCENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercentClass))
-
-typedef struct _SysprofCellRendererPercent SysprofCellRendererPercent;
-typedef struct _SysprofCellRendererPercentClass SysprofCellRendererPercentClass;
-
-struct _SysprofCellRendererPercent
-{
- SysprofCellRendererProgress parent;
-};
-
-struct _SysprofCellRendererPercentClass
-{
- SysprofCellRendererProgressClass parent_class;
-
- /*< private >*/
- gpointer _reserved[4];
-};
-
-GType sysprof_cell_renderer_percent_get_type (void);
-GtkCellRenderer *sysprof_cell_renderer_percent_new (void);
-gdouble sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self);
-void sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
- gdouble percent);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-cell-renderer-progress.c b/src/libsysprof-ui/sysprof-cell-renderer-progress.c
deleted file mode 100644
index a0943b64..00000000
--- a/src/libsysprof-ui/sysprof-cell-renderer-progress.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/* gtkcellrendererprogress.c
- * Copyright (C) 2002 Naba Kumar
- * heavily modified by Jörgen Scheibengruber
- * heavily modified by Marco Pesenti Gritti
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see .
- */
-/*
- * Modified by the GTK+ Team and others 1997-2007. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include
-#include
-
-#include "sysprof-cell-renderer-progress.h"
-
-
-enum
-{
- PROP_0,
- PROP_VALUE,
- PROP_TEXT,
- PROP_PULSE,
- PROP_TEXT_XALIGN,
- PROP_TEXT_YALIGN,
- PROP_ORIENTATION,
- PROP_INVERTED
-};
-
-struct _SysprofCellRendererProgressPrivate
-{
- int value;
- char *text;
- char *label;
- int min_h;
- int min_w;
- int pulse;
- int offset;
- float text_xalign;
- float text_yalign;
- GtkOrientation orientation;
- gboolean inverted;
-};
-
-static void sysprof_cell_renderer_progress_finalize (GObject *object);
-static void sysprof_cell_renderer_progress_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-static void sysprof_cell_renderer_progress_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec);
-static void sysprof_cell_renderer_progress_set_value (SysprofCellRendererProgress *cellprogress,
- int value);
-static void sysprof_cell_renderer_progress_set_text (SysprofCellRendererProgress *cellprogress,
- const char *text);
-static void sysprof_cell_renderer_progress_set_pulse (SysprofCellRendererProgress *cellprogress,
- int pulse);
-static void compute_dimensions (GtkCellRenderer *cell,
- GtkWidget *widget,
- const char *text,
- int *width,
- int *height);
-static void sysprof_cell_renderer_progress_snapshot (GtkCellRenderer *cell,
- GtkSnapshot *snapshot,
- GtkWidget *widget,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- GtkCellRendererState flags);
-
-
-G_DEFINE_TYPE_WITH_CODE (SysprofCellRendererProgress, sysprof_cell_renderer_progress, GTK_TYPE_CELL_RENDERER,
- G_ADD_PRIVATE (SysprofCellRendererProgress)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
-
-static void
-recompute_label (SysprofCellRendererProgress *cellprogress)
-{
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
- char *label;
-
- if (priv->text)
- label = g_strdup (priv->text);
- else if (priv->pulse < 0)
- label = g_strdup_printf (C_("progress bar label", "%d %%"), priv->value);
- else
- label = NULL;
-
- g_free (priv->label);
- priv->label = label;
-}
-
-static void
-sysprof_cell_renderer_progress_set_value (SysprofCellRendererProgress *cellprogress,
- int value)
-{
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
-
- if (priv->value != value)
- {
- priv->value = value;
- recompute_label (cellprogress);
- g_object_notify (G_OBJECT (cellprogress), "value");
- }
-}
-
-static void
-sysprof_cell_renderer_progress_set_text (SysprofCellRendererProgress *cellprogress,
- const char *text)
-{
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
- char *new_text;
-
- new_text = g_strdup (text);
- g_free (priv->text);
- priv->text = new_text;
- recompute_label (cellprogress);
- g_object_notify (G_OBJECT (cellprogress), "text");
-}
-
-static void
-sysprof_cell_renderer_progress_set_pulse (SysprofCellRendererProgress *cellprogress,
- int pulse)
-{
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
-
- if (pulse != priv->pulse)
- {
- if (pulse <= 0)
- priv->offset = 0;
- else
- priv->offset = pulse;
- g_object_notify (G_OBJECT (cellprogress), "pulse");
- }
-
- priv->pulse = pulse;
- recompute_label (cellprogress);
-}
-
-static void
-sysprof_cell_renderer_progress_finalize (GObject *object)
-{
- SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
-
- g_free (priv->text);
- g_free (priv->label);
-
- G_OBJECT_CLASS (sysprof_cell_renderer_progress_parent_class)->finalize (object);
-}
-
-static void
-sysprof_cell_renderer_progress_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
-
- switch (param_id)
- {
- case PROP_VALUE:
- g_value_set_int (value, priv->value);
- break;
- case PROP_TEXT:
- g_value_set_string (value, priv->text);
- break;
- case PROP_PULSE:
- g_value_set_int (value, priv->pulse);
- break;
- case PROP_TEXT_XALIGN:
- g_value_set_float (value, priv->text_xalign);
- break;
- case PROP_TEXT_YALIGN:
- g_value_set_float (value, priv->text_yalign);
- break;
- case PROP_ORIENTATION:
- g_value_set_enum (value, priv->orientation);
- break;
- case PROP_INVERTED:
- g_value_set_boolean (value, priv->inverted);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- }
-}
-
-static void
-sysprof_cell_renderer_progress_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
-
- switch (param_id)
- {
- case PROP_VALUE:
- sysprof_cell_renderer_progress_set_value (cellprogress,
- g_value_get_int (value));
- break;
- case PROP_TEXT:
- sysprof_cell_renderer_progress_set_text (cellprogress,
- g_value_get_string (value));
- break;
- case PROP_PULSE:
- sysprof_cell_renderer_progress_set_pulse (cellprogress,
- g_value_get_int (value));
- break;
- case PROP_TEXT_XALIGN:
- priv->text_xalign = g_value_get_float (value);
- break;
- case PROP_TEXT_YALIGN:
- priv->text_yalign = g_value_get_float (value);
- break;
- case PROP_ORIENTATION:
- if (priv->orientation != g_value_get_enum (value))
- {
- priv->orientation = g_value_get_enum (value);
- g_object_notify_by_pspec (object, pspec);
- }
- break;
- case PROP_INVERTED:
- if (priv->inverted != g_value_get_boolean (value))
- {
- priv->inverted = g_value_get_boolean (value);
- g_object_notify_by_pspec (object, pspec);
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- }
-}
-
-static void
-compute_dimensions (GtkCellRenderer *cell,
- GtkWidget *widget,
- const char *text,
- int *width,
- int *height)
-{
- PangoRectangle logical_rect;
- PangoLayout *layout;
- int xpad, ypad;
-
- layout = gtk_widget_create_pango_layout (widget, text);
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
- gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
-
- if (width)
- *width = logical_rect.width + xpad * 2;
-
- if (height)
- *height = logical_rect.height + ypad * 2;
-
- g_object_unref (layout);
-}
-
-static void
-sysprof_cell_renderer_progress_get_preferred_width (GtkCellRenderer *cell,
- GtkWidget *widget,
- int *minimum,
- int *natural)
-{
- SysprofCellRendererProgress *self = SYSPROF_CELL_RENDERER_PROGRESS (cell);
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (self);
- int w, h;
- int size;
-
- if (priv->min_w < 0)
- {
- char *text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
- compute_dimensions (cell, widget, text,
- &priv->min_w,
- &priv->min_h);
- g_free (text);
- }
-
- compute_dimensions (cell, widget, priv->label, &w, &h);
-
- size = MAX (priv->min_w, w);
-
- if (minimum != NULL)
- *minimum = size;
- if (natural != NULL)
- *natural = size;
-}
-
-static void
-sysprof_cell_renderer_progress_get_preferred_height (GtkCellRenderer *cell,
- GtkWidget *widget,
- int *minimum,
- int *natural)
-{
- SysprofCellRendererProgress *self = SYSPROF_CELL_RENDERER_PROGRESS (cell);
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (self);
- int w, h;
- int size;
-
- if (priv->min_w < 0)
- {
- char *text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
- compute_dimensions (cell, widget, text,
- &priv->min_w,
- &priv->min_h);
- g_free (text);
- }
-
- compute_dimensions (cell, widget, priv->label, &w, &h);
-
- size = MIN (priv->min_h, h);
-
- if (minimum != NULL)
- *minimum = size;
- if (natural != NULL)
- *natural = size;
-}
-
-static inline int
-get_bar_size (int pulse,
- int value,
- int full_size)
-{
- int bar_size;
-
- if (pulse < 0)
- bar_size = full_size * MAX (0, value) / 100;
- else if (pulse == 0)
- bar_size = 0;
- else if (pulse == G_MAXINT)
- bar_size = full_size;
- else
- bar_size = MAX (2, full_size / 5);
-
- return bar_size;
-}
-
-static inline int
-get_bar_position (int start,
- int full_size,
- int bar_size,
- int pulse,
- int offset,
- gboolean is_rtl)
-{
- int position;
-
- if (pulse < 0 || pulse == 0 || pulse == G_MAXINT)
- {
- position = is_rtl ? (start + full_size - bar_size) : start;
- }
- else
- {
- position = (is_rtl ? offset + 12 : offset) % 24;
- if (position > 12)
- position = 24 - position;
- position = start + full_size * position / 15;
- }
-
- return position;
-}
-
-static void
-sysprof_cell_renderer_progress_snapshot (GtkCellRenderer *cell,
- GtkSnapshot *snapshot,
- GtkWidget *widget,
- const GdkRectangle *background_area,
- const GdkRectangle *cell_area,
- GtkCellRendererState flags)
-{
- SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (cell);
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
- GtkStyleContext *context;
- GtkBorder padding;
- PangoLayout *layout;
- PangoRectangle logical_rect;
- int x, y, w, h, x_pos, y_pos, bar_position, bar_size, start, full_size;
- int xpad, ypad;
- GdkRectangle clip;
- gboolean is_rtl;
-
- context = gtk_widget_get_style_context (widget);
- is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
-
- gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
- x = cell_area->x + xpad;
- y = cell_area->y + ypad;
- w = cell_area->width - xpad * 2;
- h = cell_area->height - ypad * 2;
-
- gtk_style_context_save (context);
- gtk_style_context_add_class (context, "trough");
-
- gtk_snapshot_render_background (snapshot, context, x, y, w, h);
- gtk_snapshot_render_frame (snapshot, context, x, y, w, h);
-
- gtk_style_context_get_padding (context, &padding);
-
- x += padding.left;
- y += padding.top;
- w -= padding.left + padding.right;
- h -= padding.top + padding.bottom;
-
- gtk_style_context_restore (context);
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- clip.y = y;
- clip.height = h;
-
- start = x;
- full_size = w;
-
- bar_size = get_bar_size (priv->pulse, priv->value, full_size);
-
- if (!priv->inverted)
- bar_position = get_bar_position (start, full_size, bar_size,
- priv->pulse, priv->offset, is_rtl);
- else
- bar_position = get_bar_position (start, full_size, bar_size,
- priv->pulse, priv->offset, !is_rtl);
-
- clip.width = bar_size;
- clip.x = bar_position;
- }
- else
- {
- clip.x = x;
- clip.width = w;
-
- start = y;
- full_size = h;
-
- bar_size = get_bar_size (priv->pulse, priv->value, full_size);
-
- if (priv->inverted)
- bar_position = get_bar_position (start, full_size, bar_size,
- priv->pulse, priv->offset, TRUE);
- else
- bar_position = get_bar_position (start, full_size, bar_size,
- priv->pulse, priv->offset, FALSE);
-
- clip.height = bar_size;
- clip.y = bar_position;
- }
-
- if (bar_size > 0)
- {
- gtk_style_context_save (context);
- gtk_style_context_add_class (context, "progressbar");
-
- gtk_snapshot_render_background (snapshot, context, clip.x, clip.y, clip.width, clip.height);
- gtk_snapshot_render_frame (snapshot, context, clip.x, clip.y, clip.width, clip.height);
-
- gtk_style_context_restore (context);
- }
-
- if (priv->label)
- {
- float text_xalign;
-
- layout = gtk_widget_create_pango_layout (widget, priv->label);
- pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
- if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
- text_xalign = 1.0 - priv->text_xalign;
- else
- text_xalign = priv->text_xalign;
-
- x_pos = x + padding.left + text_xalign *
- (w - padding.left - padding.right - logical_rect.width);
-
- y_pos = y + padding.top + priv->text_yalign *
- (h - padding.top - padding.bottom - logical_rect.height);
-
- gtk_snapshot_push_clip (snapshot,
- &GRAPHENE_RECT_INIT(
- clip.x, clip.y,
- clip.width, clip.height
- ));
-
- gtk_style_context_save (context);
- gtk_style_context_add_class (context, "progressbar");
-
- gtk_snapshot_render_layout (snapshot, context,
- x_pos, y_pos,
- layout);
-
- gtk_style_context_restore (context);
- gtk_snapshot_pop (snapshot);
-
- gtk_style_context_save (context);
- gtk_style_context_add_class (context, "trough");
-
- if (bar_position > start)
- {
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- clip.x = x;
- clip.width = bar_position - x;
- }
- else
- {
- clip.y = y;
- clip.height = bar_position - y;
- }
-
- gtk_snapshot_push_clip (snapshot,
- &GRAPHENE_RECT_INIT(
- clip.x, clip.y,
- clip.width, clip.height
- ));
-
- gtk_snapshot_render_layout (snapshot, context,
- x_pos, y_pos,
- layout);
-
- gtk_snapshot_pop (snapshot);
- }
-
- if (bar_position + bar_size < start + full_size)
- {
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- clip.x = bar_position + bar_size;
- clip.width = x + w - (bar_position + bar_size);
- }
- else
- {
- clip.y = bar_position + bar_size;
- clip.height = y + h - (bar_position + bar_size);
- }
-
- gtk_snapshot_push_clip (snapshot,
- &GRAPHENE_RECT_INIT(
- clip.x, clip.y,
- clip.width, clip.height
- ));
-
- gtk_snapshot_render_layout (snapshot, context,
- x_pos, y_pos,
- layout);
-
- gtk_snapshot_pop (snapshot);
- }
-
- gtk_style_context_restore (context);
- g_object_unref (layout);
- }
-}
-
-static void
-sysprof_cell_renderer_progress_class_init (SysprofCellRendererProgressClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
-
- object_class->finalize = sysprof_cell_renderer_progress_finalize;
- object_class->get_property = sysprof_cell_renderer_progress_get_property;
- object_class->set_property = sysprof_cell_renderer_progress_set_property;
-
- cell_class->get_preferred_width = sysprof_cell_renderer_progress_get_preferred_width;
- cell_class->get_preferred_height = sysprof_cell_renderer_progress_get_preferred_height;
- cell_class->snapshot = sysprof_cell_renderer_progress_snapshot;
-
- /**
- * SysprofCellRendererProgress:value:
- *
- * The "value" property determines the percentage to which the
- * progress bar will be "filled in".
- **/
- g_object_class_install_property (object_class,
- PROP_VALUE,
- g_param_spec_int ("value",
- "Value",
- "Value of the progress bar",
- 0, 100, 0,
- G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
-
- /**
- * SysprofCellRendererProgress:text:
- *
- * The "text" property determines the label which will be drawn
- * over the progress bar. Setting this property to %NULL causes the default
- * label to be displayed. Setting this property to an empty string causes
- * no label to be displayed.
- **/
- g_object_class_install_property (object_class,
- PROP_TEXT,
- g_param_spec_string ("text",
- "Text",
- "Text on the progress bar",
- NULL,
- G_PARAM_READWRITE));
-
- /**
- * SysprofCellRendererProgress:pulse:
- *
- * Setting this to a non-negative value causes the cell renderer to
- * enter "activity mode", where a block bounces back and forth to
- * indicate that some progress is made, without specifying exactly how
- * much.
- *
- * Each increment of the property causes the block to move by a little
- * bit.
- *
- * To indicate that the activity has not started yet, set the property
- * to zero. To indicate completion, set the property to %G_MAXINT.
- */
- g_object_class_install_property (object_class,
- PROP_PULSE,
- g_param_spec_int ("pulse",
- "Pulse",
- "Set this to positive values to indicate that some progress is made, but you don’t know how much.",
- -1, G_MAXINT, -1,
- G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
-
- /**
- * SysprofCellRendererProgress:text-xalign:
- *
- * The "text-xalign" property controls the horizontal alignment of the
- * text in the progress bar. Valid values range from 0 (left) to 1
- * (right). Reserved for RTL layouts.
- */
- g_object_class_install_property (object_class,
- PROP_TEXT_XALIGN,
- g_param_spec_float ("text-xalign",
- "Text x alignment",
- "The horizontal text alignment, from 0 (left) to 1 (right). Reversed for RTL layouts.",
- 0.0, 1.0, 0.5,
- G_PARAM_READWRITE));
-
- /**
- * SysprofCellRendererProgress:text-yalign:
- *
- * The "text-yalign" property controls the vertical alignment of the
- * text in the progress bar. Valid values range from 0 (top) to 1
- * (bottom).
- */
- g_object_class_install_property (object_class,
- PROP_TEXT_YALIGN,
- g_param_spec_float ("text-yalign",
- "Text y alignment",
- "The vertical text alignment, from 0 (top) to 1 (bottom).",
- 0.0, 1.0, 0.5,
- G_PARAM_READWRITE));
-
- g_object_class_override_property (object_class,
- PROP_ORIENTATION,
- "orientation");
-
- g_object_class_install_property (object_class,
- PROP_INVERTED,
- g_param_spec_boolean ("inverted",
- "Inverted",
- "Invert the direction in which the progress bar grows",
- FALSE,
- G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
-}
-
-static void
-sysprof_cell_renderer_progress_init (SysprofCellRendererProgress *cellprogress)
-{
- SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
-
- priv->value = 0;
- priv->text = NULL;
- priv->label = NULL;
- priv->min_w = -1;
- priv->min_h = -1;
- priv->pulse = -1;
- priv->offset = 0;
-
- priv->text_xalign = 0.5;
- priv->text_yalign = 0.5;
-
- priv->orientation = GTK_ORIENTATION_HORIZONTAL,
- priv->inverted = FALSE;
-}
-
-/**
- * sysprof_cell_renderer_progress_new:
- *
- * Creates a new `SysprofCellRendererProgress`.
- *
- * Returns: the new cell renderer
- **/
-GtkCellRenderer*
-sysprof_cell_renderer_progress_new (void)
-{
- return g_object_new (SYSPROF_TYPE_CELL_RENDERER_PROGRESS, NULL);
-}
diff --git a/src/libsysprof-ui/sysprof-cell-renderer-progress.h b/src/libsysprof-ui/sysprof-cell-renderer-progress.h
deleted file mode 100644
index 7a006072..00000000
--- a/src/libsysprof-ui/sysprof-cell-renderer-progress.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* gtkcellrendererprogress.h
- * Copyright (C) 2002 Naba Kumar
- * modified by Jörgen Scheibengruber
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see .
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2004. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_CELL_RENDERER_PROGRESS (sysprof_cell_renderer_progress_get_type ())
-#define SYSPROF_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PROGRESS, SysprofCellRendererProgress))
-#define SYSPROF_IS_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SYSPROF_TYPE_CELL_RENDERER_PROGRESS))
-
-typedef struct _SysprofCellRendererProgress SysprofCellRendererProgress;
-typedef struct _SysprofCellRendererProgressClass SysprofCellRendererProgressClass;
-typedef struct _SysprofCellRendererProgressPrivate SysprofCellRendererProgressPrivate;
-
-struct _SysprofCellRendererProgress
-{
- GtkCellRenderer parent_instance;
-};
-
-struct _SysprofCellRendererProgressClass
-{
- GtkCellRendererClass parent_class;
-};
-
-GType sysprof_cell_renderer_progress_get_type (void) G_GNUC_CONST;
-GtkCellRenderer *sysprof_cell_renderer_progress_new (void);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-check.c b/src/libsysprof-ui/sysprof-check.c
deleted file mode 100644
index d7025790..00000000
--- a/src/libsysprof-ui/sysprof-check.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* sysprof-check.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-check"
-
-#include "config.h"
-
-#include "sysprof-check.h"
-
-static void
-sysprof_check_supported_ping_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GDBusConnection *bus = (GDBusConnection *)object;
- g_autoptr(GVariant) reply = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
-
- g_assert (G_IS_DBUS_CONNECTION (bus));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- if (!(reply = g_dbus_connection_call_finish (bus, result, &error)))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_check_supported_bus_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- g_autoptr(GDBusConnection) bus = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
-
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- if (!(bus = g_bus_get_finish (result, &error)))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- g_dbus_connection_call (bus,
- "org.gnome.Sysprof3",
- "/org/gnome/Sysprof3",
- "org.freedesktop.DBus.Peer",
- "Ping",
- g_variant_new ("()"),
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- g_task_get_cancellable (task),
- sysprof_check_supported_ping_cb,
- g_object_ref (task));
-}
-
-void
-sysprof_check_supported_async (GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(GTask) task = NULL;
-
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (NULL, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_check_supported_async);
-
- /* Get access to the System D-Bus and check to see if we can ping the
- * service that is found at org.gnome.Sysprof3.
- */
-
- g_bus_get (G_BUS_TYPE_SYSTEM,
- cancellable,
- sysprof_check_supported_bus_cb,
- g_steal_pointer (&task));
-
-}
-
-gboolean
-sysprof_check_supported_finish (GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
diff --git a/src/libsysprof-ui/sysprof-check.h b/src/libsysprof-ui/sysprof-check.h
deleted file mode 100644
index bb8f4e7c..00000000
--- a/src/libsysprof-ui/sysprof-check.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* sysprof-check.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-#include "sysprof-version-macros.h"
-
-G_BEGIN_DECLS
-
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_check_supported_async (GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_check_supported_finish (GAsyncResult *result,
- GError **error);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-color-cycle.c b/src/libsysprof-ui/sysprof-color-cycle.c
deleted file mode 100644
index 582878e9..00000000
--- a/src/libsysprof-ui/sysprof-color-cycle.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* sysprof-color-cycle.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-color-cycle"
-
-#include "config.h"
-
-#include "sysprof-color-cycle.h"
-
-G_DEFINE_BOXED_TYPE (SysprofColorCycle, sysprof_color_cycle, sysprof_color_cycle_ref, sysprof_color_cycle_unref)
-
-static const gchar *default_colors[] = {
-
- "#1a5fb4", /* Blue 5 */
- "#26a269", /* Green 5 */
- "#e5a50a", /* Yellow 5 */
- "#c64600", /* Orange 5 */
- "#a51d2d", /* Red 5 */
- "#613583", /* Purple 5 */
- "#63452c", /* Brown 5 */
-
- "#1c71d8", /* Blue 4 */
- "#2ec27e", /* Green 4 */
- "#f5c211", /* Yellow 4 */
- "#e66100", /* Orange 4 */
- "#c01c28", /* Red 4 */
- "#813d9c", /* Purple 4 */
- "#865e3c", /* Brown 4 */
-
- "#3584e4", /* Blue 3 */
- "#33d17a", /* Green 3 */
- "#f6d32d", /* Yellow 3 */
- "#ff7800", /* Orange 3 */
- "#e01b24", /* Red 3 */
- "#9141ac", /* Purple 3 */
- "#986a44", /* Brown 3 */
-
- "#62a0ea", /* Blue 2 */
- "#57e389", /* Green 2 */
- "#f8e45c", /* Yellow 2 */
- "#ffa348", /* Orange 2 */
- "#ed333b", /* Red 2 */
- "#c061cb", /* Purple 2 */
- "#b5835a", /* Brown 2 */
-
- "#99c1f1", /* Blue 1 */
- "#8ff0a4", /* Green 1 */
- "#f9f06b", /* Yellow 1 */
- "#ffbe6f", /* Orange 1 */
- "#f66151", /* Red 1 */
- "#dc8add", /* Purple 1 */
- "#cdab8f", /* Brown 1 */
-
- NULL
-};
-
-struct _SysprofColorCycle
-{
- volatile gint ref_count;
- GdkRGBA *colors;
- gsize n_colors;
- guint position;
-};
-
-static void
-sysprof_color_cycle_destroy (SysprofColorCycle *self)
-{
- g_free (self->colors);
- g_slice_free (SysprofColorCycle, self);
-}
-
-SysprofColorCycle *
-sysprof_color_cycle_new (void)
-{
- SysprofColorCycle *self;
-
- self = g_slice_new0 (SysprofColorCycle);
- self->ref_count = 1;
- self->n_colors = g_strv_length ((gchar **)default_colors);
- self->colors = g_new0 (GdkRGBA, self->n_colors);
-
- for (guint i = 0; default_colors[i]; i++)
- {
- if G_UNLIKELY (!gdk_rgba_parse (&self->colors[i], default_colors[i]))
- g_warning ("Failed to parse color %s into an RGBA", default_colors[i]);
- }
-
- return self;
-}
-
-SysprofColorCycle *
-sysprof_color_cycle_ref (SysprofColorCycle *self)
-{
- g_return_val_if_fail (self != NULL, NULL);
- g_return_val_if_fail (self->ref_count > 0, NULL);
- g_atomic_int_inc (&self->ref_count);
- return self;
-}
-
-void
-sysprof_color_cycle_unref (SysprofColorCycle *self)
-{
- g_return_if_fail (self != NULL);
- g_return_if_fail (self->ref_count > 0);
- if (g_atomic_int_dec_and_test (&self->ref_count))
- sysprof_color_cycle_destroy (self);
-}
-
-void
-sysprof_color_cycle_next (SysprofColorCycle *self,
- GdkRGBA *rgba)
-{
- g_return_if_fail (self != NULL);
- g_return_if_fail (self->position < self->n_colors);
-
- *rgba = self->colors[self->position];
-
- /*
- * TODO: Adjust color HSV/etc
- *
- * We could simply adjust the brightness/etc after we dispatch
- * a color so that we get darker as we go.
- */
-
- self->position = (self->position + 1) % self->n_colors;
-}
-
-void
-sysprof_color_cycle_reset (SysprofColorCycle *self)
-{
- g_return_if_fail (self != NULL);
-
- for (guint i = 0; default_colors[i]; i++)
- {
- if G_UNLIKELY (!gdk_rgba_parse (&self->colors[i], default_colors[i]))
- g_warning ("Failed to parse color %s into an RGBA", default_colors[i]);
- }
-
- self->position = 0;
-}
diff --git a/src/libsysprof-ui/sysprof-color-cycle.h b/src/libsysprof-ui/sysprof-color-cycle.h
deleted file mode 100644
index 650acb78..00000000
--- a/src/libsysprof-ui/sysprof-color-cycle.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* sysprof-color-cycle.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_COLOR_CYCLE (sysprof_color_cycle_get_type())
-
-typedef struct _SysprofColorCycle SysprofColorCycle;
-
-GType sysprof_color_cycle_get_type (void);
-SysprofColorCycle *sysprof_color_cycle_ref (SysprofColorCycle *self);
-void sysprof_color_cycle_unref (SysprofColorCycle *self);
-SysprofColorCycle *sysprof_color_cycle_new (void);
-void sysprof_color_cycle_reset (SysprofColorCycle *self);
-void sysprof_color_cycle_next (SysprofColorCycle *self,
- GdkRGBA *rgba);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofColorCycle, sysprof_color_cycle_unref)
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-counters-aid.c b/src/libsysprof-ui/sysprof-counters-aid.c
deleted file mode 100644
index 42bd04f0..00000000
--- a/src/libsysprof-ui/sysprof-counters-aid.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/* sysprof-counters-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-counters-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-counters-aid.h"
-#include "sysprof-line-visualizer.h"
-#include "sysprof-marks-page.h"
-#include "sysprof-time-visualizer.h"
-
-struct _SysprofCountersAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
-} Present;
-
-G_DEFINE_TYPE (SysprofCountersAid, sysprof_counters_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-static void
-on_group_activated_cb (SysprofVisualizerGroup *group,
- SysprofPage *page)
-{
- SysprofDisplay *display;
-
- g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
- g_assert (SYSPROF_IS_PAGE (page));
-
- display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
- sysprof_display_set_visible_page (display, page);
-}
-
-/**
- * sysprof_counters_aid_new:
- *
- * Create a new #SysprofCountersAid.
- *
- * Returns: (transfer full): a newly created #SysprofCountersAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_counters_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_COUNTERS_AID, NULL);
-}
-
-static void
-sysprof_counters_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
-}
-
-static gchar *
-build_title (const SysprofCaptureCounter *ctr)
-{
- GString *str;
-
- str = g_string_new (NULL);
-
- if (ctr->category[0] != 0)
- {
- if (str->len)
- g_string_append_c (str, ' ');
- g_string_append (str, ctr->category);
- }
-
- if (ctr->name[0] != 0)
- {
- if (str->len)
- g_string_append (str, " — ");
- g_string_append (str, ctr->name);
- }
-
- if (ctr->description[0] != 0)
- {
- if (str->len)
- g_string_append_printf (str, " (%s)", ctr->description);
- else
- g_string_append (str, ctr->description);
- }
-
- if (str->len == 0)
- /* this is untranslated on purpose */
- g_string_append_printf (str, "Counter %d", ctr->id);
-
- return g_string_free (str, FALSE);
-}
-
-static bool
-collect_counters (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
- GArray *counters = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
- g_assert (counters != NULL);
-
- if (def->n_counters > 0)
- g_array_append_vals (counters, def->counters, def->n_counters);
-
- return TRUE;
-}
-
-static void
-sysprof_counters_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *present = task_data;
- g_autoptr(GArray) counters = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_COUNTERS_AID (source_object));
- g_assert (present != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
- sysprof_capture_cursor_foreach (present->cursor, collect_counters, counters);
- g_task_return_pointer (task,
- g_steal_pointer (&counters),
- (GDestroyNotify) g_array_unref);
-}
-
-static void
-sysprof_counters_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_COUNTERS_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (1, types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_counters_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_counters_aid_present_worker);
-}
-
-static gboolean
-sysprof_counters_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- g_autoptr(GArray) counters = NULL;
- Present *present;
-
- g_assert (SYSPROF_IS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- present = g_task_get_task_data (G_TASK (result));
-
- if ((counters = g_task_propagate_pointer (G_TASK (result), error)) && counters->len > 0)
- {
- g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
- SysprofVisualizerGroup *group;
- SysprofVisualizer *combined;
- GtkWidget *page;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "has-page", TRUE,
- "title", _("Counters"),
- "visible", TRUE,
- NULL);
-
- combined = g_object_new (SYSPROF_TYPE_TIME_VISUALIZER,
- "title", _("Counters"),
- "height-request", 35,
- "visible", TRUE,
- NULL);
- sysprof_visualizer_group_insert (group, combined, -1, TRUE);
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
- g_autofree gchar *title = build_title (ctr);
- GtkWidget *row;
- GdkRGBA rgba;
-
- row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- "title", title,
- "height-request", 35,
- "visible", FALSE,
- NULL);
- sysprof_color_cycle_next (cycle, &rgba);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- rgba.alpha = .5;
- sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- sysprof_time_visualizer_add_counter (SYSPROF_TIME_VISUALIZER (combined), ctr->id, &rgba);
- sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), -1, TRUE);
- }
-
- sysprof_display_add_group (present->display, group);
-
- page = sysprof_marks_page_new (sysprof_display_get_zoom_manager (present->display),
- SYSPROF_MARKS_MODEL_COUNTERS);
- gtk_widget_show (page);
-
- g_signal_connect_object (group,
- "group-activated",
- G_CALLBACK (on_group_activated_cb),
- page,
- 0);
- sysprof_display_add_page (present->display, SYSPROF_PAGE (page));
- }
-
- return counters != NULL;
-}
-
-static void
-sysprof_counters_aid_class_init (SysprofCountersAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_counters_aid_prepare;
- aid_class->present_async = sysprof_counters_aid_present_async;
- aid_class->present_finish = sysprof_counters_aid_present_finish;
-}
-
-static void
-sysprof_counters_aid_init (SysprofCountersAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Counters"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-cpu-aid.c b/src/libsysprof-ui/sysprof-cpu-aid.c
deleted file mode 100644
index febdf876..00000000
--- a/src/libsysprof-ui/sysprof-cpu-aid.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/* sysprof-cpu-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-cpu-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-cpu-aid.h"
-#include "sysprof-line-visualizer.h"
-#include "sysprof-procs-visualizer.h"
-
-struct _SysprofCpuAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
- GArray *counters;
- guint has_processes : 1;
-} Present;
-
-G_DEFINE_TYPE (SysprofCpuAid, sysprof_cpu_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_pointer (&p->counters, g_array_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-/**
- * sysprof_cpu_aid_new:
- *
- * Create a new #SysprofCpuAid.
- *
- * Returns: (transfer full): a newly created #SysprofCpuAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_cpu_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_CPU_AID, NULL);
-}
-
-static void
-sysprof_cpu_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
-#ifdef __linux__
- g_autoptr(SysprofSource) source = NULL;
-
- g_assert (SYSPROF_IS_CPU_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- source = sysprof_hostinfo_source_new ();
- sysprof_profiler_add_source (profiler, source);
-#endif
-}
-
-static bool
-collect_info (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
- Present *p = user_data;
-
- g_assert (frame != NULL);
- g_assert (p != NULL);
- g_assert (p->counters != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
- {
- for (guint i = 0; i < def->n_counters; i++)
- {
- const SysprofCaptureCounter *counter = &def->counters[i];
-
- if (g_strcmp0 (counter->category, "CPU Percent") == 0 ||
- g_strcmp0 (counter->category, "CPU Frequency") == 0)
- g_array_append_vals (p->counters, counter, 1);
- }
- }
- else if (!p->has_processes &&
- (frame->type == SYSPROF_CAPTURE_FRAME_PROCESS ||
- frame->type == SYSPROF_CAPTURE_FRAME_EXIT))
- {
- p->has_processes = TRUE;
- }
-
- return TRUE;
-}
-
-static void
-sysprof_cpu_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *present = task_data;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_CPU_AID (source_object));
- g_assert (present != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- sysprof_capture_cursor_foreach (present->cursor, collect_info, present);
- g_task_return_pointer (task,
- g_steal_pointer (&present->counters),
- (GDestroyNotify) g_array_unref);
-}
-
-static void
-sysprof_cpu_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = {
- SYSPROF_CAPTURE_FRAME_CTRDEF,
- SYSPROF_CAPTURE_FRAME_PROCESS,
- SYSPROF_CAPTURE_FRAME_EXIT,
- };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_CPU_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
- present.counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
- present.has_processes = FALSE;
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_cpu_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_cpu_aid_present_worker);
-}
-
-static gboolean
-sysprof_cpu_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- g_autoptr(GArray) counters = NULL;
- Present *present;
-
- g_assert (SYSPROF_IS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- present = g_task_get_task_data (G_TASK (result));
-
- if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
- {
- g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
- g_autoptr(SysprofColorCycle) freq_cycle = sysprof_color_cycle_new ();
- SysprofVisualizerGroup *usage;
- SysprofVisualizerGroup *freq;
- SysprofVisualizer *freq_row = NULL;
- SysprofVisualizer *over_row = NULL;
- gboolean found_combined = FALSE;
- gboolean has_usage = FALSE;
- gboolean has_freq = FALSE;
-
- usage = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "priority", -1000,
- "title", _("CPU Usage"),
- "visible", TRUE,
- NULL);
-
- freq = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "priority", -999,
- "title", _("CPU Frequency"),
- "visible", TRUE,
- NULL);
- freq_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- "title", _("CPU Frequency (All)"),
- "height-request", 35,
- "visible", TRUE,
- "y-lower", 0.0,
- "y-upper", 100.0,
- NULL);
- sysprof_visualizer_group_insert (freq, freq_row, -1, FALSE);
-
- over_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- "title", _("CPU Usage (All)"),
- "height-request", 35,
- "visible", TRUE,
- "y-lower", 0.0,
- "y-upper", 100.0,
- NULL);
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
-
- if (g_strcmp0 (ctr->category, "CPU Percent") == 0)
- {
- if (strstr (ctr->name, "Combined") != NULL)
- {
- GtkWidget *row;
- GdkRGBA rgba;
-
- found_combined = TRUE;
-
- gdk_rgba_parse (&rgba, "#1a5fb4");
- row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- /* Translators: CPU is the processor. */
- "title", _("CPU Usage (All)"),
- "height-request", 35,
- "visible", TRUE,
- "y-lower", 0.0,
- "y-upper", 100.0,
- NULL);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- rgba.alpha = 0.5;
- sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), 0, FALSE);
- has_usage = TRUE;
- }
- else if (g_str_has_prefix (ctr->name, "Total CPU "))
- {
- GtkWidget *row;
- GdkRGBA rgba;
-
- sysprof_color_cycle_next (cycle, &rgba);
- row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- "title", ctr->name,
- "height-request", 35,
- "visible", FALSE,
- "y-lower", 0.0,
- "y-upper", 100.0,
- NULL);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (over_row), ctr->id, &rgba);
- rgba.alpha = 0.5;
- sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
- has_usage = TRUE;
- }
- }
- else if (g_strcmp0 (ctr->category, "CPU Frequency") == 0)
- {
- if (g_str_has_prefix (ctr->name, "CPU "))
- {
- g_autofree gchar *title = g_strdup_printf ("%s Frequency", ctr->name);
- GtkWidget *row;
- GdkRGBA rgba;
-
- sysprof_color_cycle_next (freq_cycle, &rgba);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, &rgba);
- sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, TRUE);
-
- row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
- "title", title,
- "height-request", 35,
- "visible", FALSE,
- "y-lower", 0.0,
- "y-upper", 100.0,
- NULL);
- sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
- sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (row), ctr->id, TRUE);
- sysprof_visualizer_group_insert (freq, SYSPROF_VISUALIZER (row), -1, TRUE);
-
- has_freq = TRUE;
- }
- }
- }
-
- if (present->has_processes)
- {
- GtkWidget *row;
-
- row = g_object_new (SYSPROF_TYPE_PROCS_VISUALIZER,
- "title", _("Processes"),
- "height-request", 35,
- "visible", FALSE,
- NULL);
- sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
- }
-
- if (has_usage && !found_combined)
- sysprof_visualizer_group_insert (usage, over_row, 0, FALSE);
- else
- g_object_unref (g_object_ref_sink (over_row));
-
- if (has_usage)
- sysprof_display_add_group (present->display, usage);
- else
- g_object_unref (g_object_ref_sink (usage));
-
- if (has_freq)
- sysprof_display_add_group (present->display, freq);
- else
- g_object_unref (g_object_ref_sink (freq));
- }
-
- return counters != NULL;
-}
-
-static void
-sysprof_cpu_aid_class_init (SysprofCpuAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_cpu_aid_prepare;
- aid_class->present_async = sysprof_cpu_aid_present_async;
- aid_class->present_finish = sysprof_cpu_aid_present_finish;
-}
-
-static void
-sysprof_cpu_aid_init (SysprofCpuAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("CPU Usage"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-depth-visualizer.c b/src/libsysprof-ui/sysprof-depth-visualizer.c
deleted file mode 100644
index c98e46d8..00000000
--- a/src/libsysprof-ui/sysprof-depth-visualizer.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* sysprof-depth-visualizer.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-depth-visualizer"
-
-#include "config.h"
-
-#include
-
-#include "pointcache.h"
-#include "sysprof-depth-visualizer.h"
-
-struct _SysprofDepthVisualizer
-{
- SysprofVisualizer parent_instance;
- SysprofCaptureReader *reader;
- PointCache *points;
- guint reload_source;
- guint mode;
- int last_width;
- int last_height;
- guint reloading : 1;
- guint needs_reload : 1;
-};
-
-typedef struct
-{
- SysprofCaptureReader *reader;
- PointCache *pc;
- gint64 begin_time;
- gint64 end_time;
- gint64 duration;
- guint max_n_addrs;
- guint mode;
-} State;
-
-static void sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self);
-
-G_DEFINE_TYPE (SysprofDepthVisualizer, sysprof_depth_visualizer, SYSPROF_TYPE_VISUALIZER)
-
-static void
-state_free (State *st)
-{
- g_clear_pointer (&st->reader, sysprof_capture_reader_unref);
- g_clear_pointer (&st->pc, point_cache_unref);
- g_slice_free (State, st);
-}
-
-static bool
-discover_max_n_addr (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
- State *st = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
- g_assert (st != NULL);
-
- st->max_n_addrs = MAX (st->max_n_addrs, sample->n_addrs);
-
- return TRUE;
-}
-
-static bool
-build_point_cache_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
- State *st = user_data;
- gdouble x, y;
- gboolean has_kernel = FALSE;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
- g_assert (st != NULL);
-
- x = (frame->time - st->begin_time) / (gdouble)st->duration;
- y = sample->n_addrs / (gdouble)st->max_n_addrs;
-
- /* If this contains a context-switch (meaning we're going into the kernel
- * to do some work, use a negative value for Y so that we know later on
- * that we should draw it with a different color (after removing the negation
- * on the value.
- *
- * We skip past the first index, which is always a context switch as it is
- * our perf handler.
- */
- for (guint i = 1; i < sample->n_addrs; i++)
- {
- SysprofAddressContext kind;
-
- if (sysprof_address_is_context_switch (sample->addrs[i], &kind))
- {
- has_kernel = TRUE;
- y = -y;
- break;
- }
- }
-
- if (!has_kernel)
- point_cache_add_point_to_set (st->pc, 1, x, y);
- else
- point_cache_add_point_to_set (st->pc, 2, x, y);
-
- return TRUE;
-}
-
-static void
-sysprof_depth_visualizer_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE, };
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- SysprofCaptureCondition *condition;
- State *st = task_data;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_DEPTH_VISUALIZER (source_object));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- if (st->duration != 0)
- {
- cursor = sysprof_capture_cursor_new (st->reader);
- condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- sysprof_capture_cursor_foreach (cursor, discover_max_n_addr, st);
- sysprof_capture_cursor_reset (cursor);
- sysprof_capture_cursor_foreach (cursor, build_point_cache_cb, st);
- }
-
- g_task_return_pointer (task,
- g_steal_pointer (&st->pc),
- (GDestroyNotify) point_cache_unref);
-}
-
-static void
-apply_point_cache_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
- PointCache *pc;
-
- g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
- g_assert (G_IS_TASK (result));
-
- self->reloading = FALSE;
-
- if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
- {
- g_clear_pointer (&self->points, point_cache_unref);
- self->points = g_steal_pointer (&pc);
- gtk_widget_queue_draw (GTK_WIDGET (self));
- }
-
- if (self->needs_reload)
- sysprof_depth_visualizer_reload (self);
-}
-
-static void
-sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self)
-{
- g_autoptr(GTask) task = NULL;
- GtkAllocation alloc;
- State *st;
-
- g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
-
- self->needs_reload = TRUE;
-
- if (self->reloading)
- return;
-
- self->reloading = TRUE;
- self->needs_reload = FALSE;
-
- gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
-
- st = g_slice_new0 (State);
- st->reader = sysprof_capture_reader_ref (self->reader);
- st->pc = point_cache_new ();
- st->max_n_addrs = 0;
- st->begin_time = sysprof_capture_reader_get_start_time (self->reader);
- st->end_time = sysprof_capture_reader_get_end_time (self->reader);
- st->duration = st->end_time - st->begin_time;
- st->mode = self->mode;
-
- point_cache_add_set (st->pc, 1);
- point_cache_add_set (st->pc, 2);
-
- task = g_task_new (self, NULL, apply_point_cache_cb, NULL);
- g_task_set_source_tag (task, sysprof_depth_visualizer_reload);
- g_task_set_task_data (task, st, (GDestroyNotify) state_free);
- g_task_run_in_thread (task, sysprof_depth_visualizer_worker);
-}
-
-static void
-sysprof_depth_visualizer_set_reader (SysprofVisualizer *row,
- SysprofCaptureReader *reader)
-{
- SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)row;
-
- g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
-
- if (self->reader != reader)
- {
- if (self->reader != NULL)
- {
- sysprof_capture_reader_unref (self->reader);
- self->reader = NULL;
- }
-
- if (reader != NULL)
- {
- self->reader = sysprof_capture_reader_ref (reader);
- sysprof_depth_visualizer_reload (self);
- }
- }
-}
-
-static void
-sysprof_depth_visualizer_snapshot (GtkWidget *widget,
- GtkSnapshot *snapshot)
-{
- SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
- GtkAllocation alloc;
- GdkRectangle clip;
- const Point *points;
- cairo_t *cr;
- guint n_points = 0;
- GdkRGBA user;
- GdkRGBA system;
-
- g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
- g_assert (snapshot != NULL);
-
- GTK_WIDGET_CLASS (sysprof_depth_visualizer_parent_class)->snapshot (widget, snapshot);
-
- if (self->points == NULL)
- return;
-
- gdk_rgba_parse (&user, "#1a5fb4");
- gdk_rgba_parse (&system, "#3584e4");
-
- gtk_widget_get_allocation (widget, &alloc);
-
- cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
-
- /* FIXME: we should abstract visualizer drawing into regions so that we
- * can still know the region we're drawing.
- */
-#if 0
- if (!gdk_cairo_get_clip_rectangle (cr, &clip))
- return;
-#else
- clip.x = alloc.x = 0;
- clip.y = alloc.y = 0;
- clip.width = alloc.width;
- clip.height = alloc.height;
-#endif
-
- /* Draw user-space stacks */
- if (self->mode != SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY &&
- (points = point_cache_get_points (self->points, 1, &n_points)))
- {
- g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
-
- out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
- sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
- (const SysprofVisualizerRelativePoint *)points,
- n_points, out_points, n_points);
-
- cairo_set_line_width (cr, 1.0);
- gdk_cairo_set_source_rgba (cr, &user);
-
- for (guint i = 0; i < n_points; i++)
- {
- gdouble x, y;
-
- x = out_points[i].x;
- y = out_points[i].y;
-
- if (x < clip.x)
- continue;
-
- if (x > clip.x + clip.width)
- break;
-
- for (guint j = i + 1; j < n_points; j++)
- {
- if (out_points[j].x != x)
- break;
-
- y = MIN (y, out_points[j].y);
- }
-
- x += alloc.x;
-
- cairo_move_to (cr, (guint)x + .5, alloc.height);
- cairo_line_to (cr, (guint)x + .5, y);
- }
-
- cairo_stroke (cr);
- }
-
- /* Draw kernel-space stacks */
- if (self->mode != SYSPROF_DEPTH_VISUALIZER_USER_ONLY &&
- (points = point_cache_get_points (self->points, 2, &n_points)))
- {
- g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
-
- out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
- sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
- (const SysprofVisualizerRelativePoint *)points,
- n_points, out_points, n_points);
-
- cairo_set_line_width (cr, 1.0);
- gdk_cairo_set_source_rgba (cr, &system);
-
- for (guint i = 0; i < n_points; i++)
- {
- gdouble x, y;
-
- x = out_points[i].x;
- y = out_points[i].y;
-
- if (x < clip.x)
- continue;
-
- if (x > clip.x + clip.width)
- break;
-
- for (guint j = i + 1; j < n_points; j++)
- {
- if (out_points[j].x != x)
- break;
-
- y = MIN (y, out_points[j].y);
- }
-
- x += alloc.x;
-
- cairo_move_to (cr, (guint)x + .5, alloc.height);
- cairo_line_to (cr, (guint)x + .5, y);
- }
-
- cairo_stroke (cr);
- }
-
- cairo_destroy (cr);
-}
-
-static gboolean
-sysprof_depth_visualizer_do_reload (gpointer data)
-{
- SysprofDepthVisualizer *self = data;
- self->reload_source = 0;
- sysprof_depth_visualizer_reload (self);
- return G_SOURCE_REMOVE;
-}
-
-static void
-sysprof_depth_visualizer_queue_reload (SysprofDepthVisualizer *self)
-{
- g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
-
- g_clear_handle_id (&self->reload_source, g_source_remove);
- self->reload_source = g_idle_add (sysprof_depth_visualizer_do_reload, self);
-}
-
-static void
-sysprof_depth_visualizer_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline)
-{
- SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
-
- if (width != self->last_width || height != self->last_height)
- {
- sysprof_depth_visualizer_queue_reload (SYSPROF_DEPTH_VISUALIZER (widget));
- self->last_width = width;
- self->last_height = height;
- }
-}
-
-static void
-sysprof_depth_visualizer_finalize (GObject *object)
-{
- SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
-
- g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
- g_clear_handle_id (&self->reload_source, g_source_remove);
-
- G_OBJECT_CLASS (sysprof_depth_visualizer_parent_class)->finalize (object);
-}
-
-static void
-sysprof_depth_visualizer_class_init (SysprofDepthVisualizerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofVisualizerClass *row_class = SYSPROF_VISUALIZER_CLASS (klass);
-
- object_class->finalize = sysprof_depth_visualizer_finalize;
-
- widget_class->snapshot = sysprof_depth_visualizer_snapshot;
- widget_class->size_allocate = sysprof_depth_visualizer_size_allocate;
-
- row_class->set_reader = sysprof_depth_visualizer_set_reader;
-}
-
-static void
-sysprof_depth_visualizer_init (SysprofDepthVisualizer *self)
-{
-}
-
-SysprofVisualizer *
-sysprof_depth_visualizer_new (SysprofDepthVisualizerMode mode)
-{
- SysprofDepthVisualizer *self;
-
- g_return_val_if_fail (mode == SYSPROF_DEPTH_VISUALIZER_COMBINED ||
- mode == SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY ||
- mode == SYSPROF_DEPTH_VISUALIZER_USER_ONLY,
- NULL);
-
- self = g_object_new (SYSPROF_TYPE_DEPTH_VISUALIZER, NULL);
- self->mode = mode;
-
- return SYSPROF_VISUALIZER (g_steal_pointer (&self));
-}
diff --git a/src/libsysprof-ui/sysprof-details-page.c b/src/libsysprof-ui/sysprof-details-page.c
deleted file mode 100644
index 0bcffa02..00000000
--- a/src/libsysprof-ui/sysprof-details-page.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/* sysprof-details-page.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-details-page"
-
-#include "config.h"
-
-#include
-#include
-
-#include "sysprof-mark-detail.h"
-#include "sysprof-details-page.h"
-#include "sysprof-ui-private.h"
-
-struct _SysprofDetailsPage
-{
- GtkWidget parent_instance ;
-
- /* Template Objects */
-
- GListStore *marks_store;
- GtkSortListModel *mark_sort_model;
- GtkLabel *counters;
- GtkLabel *duration;
- GtkLabel *filename;
- GtkLabel *allocations;
- GtkLabel *forks;
- GtkLabel *marks;
- GtkLabel *processes;
- GtkLabel *samples;
- GtkLabel *start_time;
- GtkLabel *cpu_label;
-
- guint next_row;
-};
-
-G_DEFINE_TYPE (SysprofDetailsPage, sysprof_details_page, GTK_TYPE_WIDGET)
-
-#if GLIB_CHECK_VERSION(2, 56, 0)
-# define _g_date_time_new_from_iso8601 g_date_time_new_from_iso8601
-#else
-static GDateTime *
-_g_date_time_new_from_iso8601 (const gchar *str,
- GTimeZone *default_tz)
-{
- GTimeVal tv;
-
- if (g_time_val_from_iso8601 (str, &tv))
- {
- g_autoptr(GDateTime) dt = g_date_time_new_from_timeval_utc (&tv);
-
- if (default_tz)
- return g_date_time_to_timezone (dt, default_tz);
- else
- return g_steal_pointer (&dt);
- }
-
- return NULL;
-}
-#endif
-
-char *
-format_time (GObject *unused,
- gint64 time)
-{
- return time ? _sysprof_format_duration (time) : g_strdup("—");
-}
-
-static void
-sysprof_details_page_dispose (GObject *object)
-{
- SysprofDetailsPage *self = (SysprofDetailsPage *)object;
- GtkWidget *child;
-
- while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
- gtk_widget_unparent (child);
-
- G_OBJECT_CLASS (sysprof_details_page_parent_class)->dispose (object);
-}
-
-static void
-sysprof_details_page_class_init (SysprofDetailsPageClass *klass)
-{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = sysprof_details_page_dispose;
-
- g_type_ensure (SYSPROF_TYPE_MARK_DETAIL);
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-details-page.ui");
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, allocations);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, counters);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, cpu_label);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, duration);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, filename);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, forks);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks_store);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, mark_sort_model);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, processes);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, samples);
- gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, start_time);
- gtk_widget_class_bind_template_callback (widget_class, format_time);
-}
-
-static void
-sysprof_details_page_init (SysprofDetailsPage *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-
- self->next_row = 8;
-}
-
-GtkWidget *
-sysprof_details_page_new (void)
-{
- return g_object_new (SYSPROF_TYPE_DETAILS_PAGE, NULL);
-}
-
-static void
-update_cpu_info_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- g_autoptr(SysprofDetailsPage) self = user_data;
- g_autofree gchar *str = NULL;
-
- g_assert (SYSPROF_IS_DETAILS_PAGE (self));
- g_assert (G_IS_TASK (result));
-
- if ((str = g_task_propagate_pointer (G_TASK (result), NULL)))
- gtk_label_set_label (self->cpu_label, str);
-}
-
-static bool
-cpu_info_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- const SysprofCaptureFileChunk *fc = (gpointer)frame;
- const gchar *endptr;
- const gchar *line;
- gchar **str = user_data;
-
- line = memmem ((gchar *)fc->data, fc->len, "model name", 10);
-
- if (!line)
- return FALSE;
-
- endptr = (gchar *)fc->data + fc->len;
- endptr = memchr (line, '\n', endptr - line);
-
- if (endptr)
- {
- gchar *tmp = *str = g_strndup (line, endptr - line);
- for (; *tmp && *tmp != ':'; tmp++)
- *tmp = ' ';
- if (*tmp == ':')
- *tmp = ' ';
- g_strstrip (*str);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-sysprof_details_page_update_cpu_info_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- SysprofCaptureCursor *cursor = task_data;
- gchar *str = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (cursor != NULL);
-
- sysprof_capture_cursor_foreach (cursor, cpu_info_cb, &str);
- g_task_return_pointer (task, g_steal_pointer (&str), g_free);
-}
-
-static void
-sysprof_details_page_update_cpu_info (SysprofDetailsPage *self,
- SysprofCaptureReader *reader)
-{
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
-
- g_assert (SYSPROF_IS_DETAILS_PAGE (self));
- g_assert (reader != NULL);
-
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor,
- sysprof_capture_condition_new_where_file ("/proc/cpuinfo"));
-
- task = g_task_new (NULL, NULL, update_cpu_info_cb, g_object_ref (self));
- g_task_set_task_data (task,
- g_steal_pointer (&cursor),
- (GDestroyNotify) sysprof_capture_cursor_unref);
- g_task_run_in_thread (task, sysprof_details_page_update_cpu_info_worker);
-}
-
-void
-sysprof_details_page_set_reader (SysprofDetailsPage *self,
- SysprofCaptureReader *reader)
-{
- g_autoptr(GDateTime) dt = NULL;
- g_autoptr(GDateTime) local = NULL;
- g_autofree gchar *duration_str = NULL;
- const gchar *filename;
- const gchar *capture_at;
- SysprofCaptureStat st_buf;
- gint64 duration;
-
- g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
- g_return_if_fail (reader != NULL);
-
- sysprof_details_page_update_cpu_info (self, reader);
-
- if (!(filename = sysprof_capture_reader_get_filename (reader)))
- filename = _("Memory Capture");
-
- gtk_label_set_label (self->filename, filename);
-
- if ((capture_at = sysprof_capture_reader_get_time (reader)) &&
- (dt = _g_date_time_new_from_iso8601 (capture_at, NULL)) &&
- (local = g_date_time_to_local (dt)))
- {
- g_autofree gchar *str = g_date_time_format (local, "%x %X");
- gtk_label_set_label (self->start_time, str);
- }
-
- duration = sysprof_capture_reader_get_end_time (reader) -
- sysprof_capture_reader_get_start_time (reader);
- duration_str = g_strdup_printf (_("%0.4lf seconds"), duration / (gdouble)SYSPROF_NSEC_PER_SEC);
- gtk_label_set_label (self->duration, duration_str);
-
- if (sysprof_capture_reader_get_stat (reader, &st_buf))
- {
-#define SET_FRAME_COUNT(field, TYPE) \
- G_STMT_START { \
- g_autofree gchar *str = NULL; \
- str = g_strdup_printf ("%"G_GSIZE_FORMAT, st_buf.frame_count[TYPE]); \
- gtk_label_set_label (self->field, str); \
- } G_STMT_END
-
- SET_FRAME_COUNT (samples, SYSPROF_CAPTURE_FRAME_SAMPLE);
- SET_FRAME_COUNT (marks, SYSPROF_CAPTURE_FRAME_MARK);
- SET_FRAME_COUNT (processes, SYSPROF_CAPTURE_FRAME_PROCESS);
- SET_FRAME_COUNT (forks, SYSPROF_CAPTURE_FRAME_FORK);
- SET_FRAME_COUNT (counters, SYSPROF_CAPTURE_FRAME_CTRSET);
- SET_FRAME_COUNT (allocations, SYSPROF_CAPTURE_FRAME_ALLOCATION);
-
-#undef SET_FRAME_COUNT
- }
-}
-
-void
-sysprof_details_page_add_mark (SysprofDetailsPage *self,
- const gchar *mark,
- gint64 min,
- gint64 max,
- gint64 avg,
- gint64 hits)
-{
- SysprofMarkDetail *detail;
-
- g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
-
- detail = sysprof_mark_detail_new (mark, min, max, avg, hits);
-
- g_list_store_append (self->marks_store, detail);
- /*gtk_list_store_append (self->marks_store, &iter);
- gtk_list_store_set (self->marks_store, &iter,
- 0, mark,
- 1, min ? _sysprof_format_duration (min) : "—",
- 2, max ? _sysprof_format_duration (max) : "—",
- 3, avg ? _sysprof_format_duration (avg) : "—",
- 4, hits,
- 5, detail,
- -1);*/
- g_object_unref (detail);
-}
-
-void
-sysprof_details_page_add_marks (SysprofDetailsPage *self,
- const SysprofMarkStat *marks,
- guint n_marks)
-{
- g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
- g_return_if_fail (marks != NULL || n_marks == 0);
-
- if (marks == NULL || n_marks == 0)
- return;
-
- /* Be reasonable */
- if (n_marks > 100)
- n_marks = 100;
-
- for (guint i = 0; i < n_marks; i++)
- sysprof_details_page_add_mark (self,
- marks[i].name,
- marks[i].min,
- marks[i].max,
- marks[i].avg,
- marks[i].count);
-}
diff --git a/src/libsysprof-ui/sysprof-details-page.h b/src/libsysprof-ui/sysprof-details-page.h
deleted file mode 100644
index 63b919fc..00000000
--- a/src/libsysprof-ui/sysprof-details-page.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* sysprof-details-page.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-#include
-
-G_BEGIN_DECLS
-
-SYSPROF_ALIGNED_BEGIN (8)
-typedef struct
-{
- gchar name[152];
- guint64 count;
- gint64 max;
- gint64 min;
- gint64 avg;
- guint64 avg_count;
-} SysprofMarkStat
-SYSPROF_ALIGNED_END (8);
-
-#define SYSPROF_TYPE_DETAILS_PAGE (sysprof_details_page_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofDetailsPage, sysprof_details_page, SYSPROF, DETAILS_PAGE, GtkWidget)
-
-GtkWidget *sysprof_details_page_new (void);
-void sysprof_details_page_set_reader (SysprofDetailsPage *self,
- SysprofCaptureReader *reader);
-void sysprof_details_page_add_marks (SysprofDetailsPage *self,
- const SysprofMarkStat *marks,
- guint n_marks);
-void sysprof_details_page_add_mark (SysprofDetailsPage *self,
- const gchar *mark,
- gint64 min,
- gint64 max,
- gint64 avg,
- gint64 hits);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-details-page.ui b/src/libsysprof-ui/sysprof-details-page.ui
deleted file mode 100644
index e9de42de..00000000
--- a/src/libsysprof-ui/sysprof-details-page.ui
+++ /dev/null
@@ -1,361 +0,0 @@
-
-
-
-
-
-
-
- Capture
-
-
- false
- Location
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Recorded At
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Duration
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- CPU Model
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
-
-
- Statistics
-
-
- false
- Stack Traces
- Number of stack traces sampled for performance callgraphs
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Marks
- Number of marks seen
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Processes
- Number of processes seen
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Forks
- Number of times a process forked
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Memory Allocations
- Number of stack traces recorded for tracing memory allocations
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
- false
- Counters
- Number of recorded counter values
-
-
- true
- 1
- start
- true
-
-
-
-
-
-
-
-
- Statistics
-
-
- 500
- 100
-
-
- mark_sort_model
-
-
-
-
-
- Mark
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- end
-
-
- GtkListItem
-
-
-
-
-
-
- ]]>
-
-
-
-
-
-
- Hits
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- GtkListItem
-
-
-
-
-
-
- ]]>
-
-
-
-
-
-
- Min
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- GtkListItem
-
-
-
-
-
-
- ]]>
-
-
-
-
-
-
- Max
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- GtkListItem
-
-
-
-
-
-
- ]]>
-
-
-
-
-
-
- Avg
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- GtkListItem
-
-
-
-
-
-
- ]]>
-
-
-
-
-
-
-
-
-
-
-
-
- marks_store
- true
-
- marks_view
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-diskstat-aid.c b/src/libsysprof-ui/sysprof-diskstat-aid.c
deleted file mode 100644
index 676ea4a3..00000000
--- a/src/libsysprof-ui/sysprof-diskstat-aid.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/* sysprof-diskstat-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-diskstat-aid"
-
-#include "config.h"
-
-#include
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-duplex-visualizer.h"
-#include "sysprof-diskstat-aid.h"
-
-struct _SysprofDiskstatAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
-} Present;
-
-G_DEFINE_TYPE (SysprofDiskstatAid, sysprof_diskstat_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-/**
- * sysprof_diskstat_aid_new:
- *
- * Create a new #SysprofDiskstatAid.
- *
- * Returns: (transfer full): a newly created #SysprofDiskstatAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_diskstat_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_DISKSTAT_AID, NULL);
-}
-
-static void
-sysprof_diskstat_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
- g_autoptr(SysprofSource) source = NULL;
-
- g_assert (SYSPROF_IS_DISKSTAT_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- source = sysprof_diskstat_source_new ();
- sysprof_profiler_add_source (profiler, source);
-}
-
-static bool
-collect_diskstat_counters (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
- GArray *counters = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
- g_assert (counters != NULL);
-
- for (guint i = 0; i < def->n_counters; i++)
- {
- const SysprofCaptureCounter *counter = &def->counters[i];
-
- if (strcmp (counter->category, "Disk") == 0 &&
- (g_str_has_prefix (counter->name, "Total Reads") ||
- g_str_has_prefix (counter->name, "Total Writes")))
- g_array_append_vals (counters, counter, 1);
- }
-
- return TRUE;
-}
-
-static void
-sysprof_diskstat_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *present = task_data;
- g_autoptr(GArray) counters = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_DISKSTAT_AID (source_object));
- g_assert (present != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
- sysprof_capture_cursor_foreach (present->cursor, collect_diskstat_counters, counters);
- g_task_return_pointer (task,
- g_steal_pointer (&counters),
- (GDestroyNotify) g_array_unref);
-}
-
-static guint
-find_other_id (GArray *counters,
- const gchar *name)
-{
- g_autofree gchar *other = NULL;
-
- g_assert (counters);
- g_assert (name != NULL);
- g_assert (g_str_has_prefix (name, "Total Reads"));
-
- other = g_strdup_printf ("Total Writes%s", name + strlen ("Total Reads"));
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *c = &g_array_index (counters, SysprofCaptureCounter, i);
-
- if (g_str_equal (c->name, other))
- return c->id;
- }
-
- return 0;
-}
-
-static void
-sysprof_diskstat_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_DISKSTAT_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (1, types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_diskstat_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_diskstat_aid_present_worker);
-}
-
-static gboolean
-sysprof_diskstat_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- g_autoptr(GArray) counters = NULL;
- Present *present;
-
- g_assert (SYSPROF_IS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- present = g_task_get_task_data (G_TASK (result));
-
- if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
- {
- g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
- SysprofVisualizerGroup *group;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "title", _("Disk"),
- "visible", TRUE,
- NULL);
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
-
- if (g_str_has_prefix (ctr->name, "Total Reads"))
- {
- g_autofree gchar *title = NULL;
- gboolean is_combined;
- GtkWidget *row;
- GdkRGBA rgba;
- guint other_id;
-
- if (!(other_id = find_other_id (counters, ctr->name)))
- continue;
-
- is_combined = g_str_equal (ctr->description, "Combined");
-
- if (is_combined)
- title = g_strdup ("Disk Reads/Writes (All)");
- else
- title = g_strdup_printf ("Disk Reads/Writes%s", ctr->name + strlen ("Total Reads"));
-
- row = g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER,
- "title", title,
- "height-request", 35,
- "visible", is_combined,
- NULL);
- sysprof_color_cycle_next (cycle, &rgba);
- sysprof_duplex_visualizer_set_counters (SYSPROF_DUPLEX_VISUALIZER (row), ctr->id, other_id);
- sysprof_duplex_visualizer_set_colors (SYSPROF_DUPLEX_VISUALIZER (row), &rgba, &rgba);
- sysprof_duplex_visualizer_set_labels (SYSPROF_DUPLEX_VISUALIZER (row), _("Reads"), _("Writes"));
- sysprof_duplex_visualizer_set_use_diff (SYSPROF_DUPLEX_VISUALIZER (row), FALSE);
- sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), is_combined ? 0 : -1, !is_combined);
- }
- }
-
- if (counters->len > 0)
- sysprof_display_add_group (present->display, group);
- else
- g_object_unref (g_object_ref_sink (group));
- }
-
- return counters != NULL;
-}
-
-static void
-sysprof_diskstat_aid_class_init (SysprofDiskstatAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_diskstat_aid_prepare;
- aid_class->present_async = sysprof_diskstat_aid_present_async;
- aid_class->present_finish = sysprof_diskstat_aid_present_finish;
-}
-
-static void
-sysprof_diskstat_aid_init (SysprofDiskstatAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Disk"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "drive-harddisk-system-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-diskstat-aid.h b/src/libsysprof-ui/sysprof-diskstat-aid.h
deleted file mode 100644
index c2938a41..00000000
--- a/src/libsysprof-ui/sysprof-diskstat-aid.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* sysprof-diskstat-aid.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-aid.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_DISKSTAT_AID (sysprof_diskstat_aid_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofDiskstatAid, sysprof_diskstat_aid, SYSPROF, DISKSTAT_AID, SysprofAid)
-
-SysprofAid *sysprof_diskstat_aid_new (void);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-display.c b/src/libsysprof-ui/sysprof-display.c
deleted file mode 100644
index 0c0ac27c..00000000
--- a/src/libsysprof-ui/sysprof-display.c
+++ /dev/null
@@ -1,1340 +0,0 @@
-/* sysprof-display.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-display"
-
-#include "config.h"
-
-#include
-
-#include "egg-paned-private.h"
-
-#include "sysprof-details-page.h"
-#include "sysprof-display-private.h"
-#include "sysprof-profiler-assistant.h"
-#include "sysprof-failed-state-view.h"
-#include "sysprof-recording-state-view.h"
-#include "sysprof-theme-manager.h"
-#include "sysprof-ui-private.h"
-#include "sysprof-visualizers-frame.h"
-#include "sysprof-visualizer-group-private.h"
-
-#include "sysprof-battery-aid.h"
-#include "sysprof-callgraph-aid.h"
-#include "sysprof-counters-aid.h"
-#include "sysprof-cpu-aid.h"
-#include "sysprof-diskstat-aid.h"
-#include "sysprof-logs-aid.h"
-#include "sysprof-marks-aid.h"
-#include "sysprof-memory-aid.h"
-#include "sysprof-memprof-aid.h"
-#include "sysprof-netdev-aid.h"
-#include "sysprof-rapl-aid.h"
-
-typedef enum
-{
- SYSPROF_CAPTURE_FLAGS_CAN_REPLAY = 1 << 1,
-} SysprofCaptureFlags;
-
-typedef struct
-{
- SysprofCaptureReader *reader;
- SysprofCaptureCondition *filter;
- GFile *file;
- SysprofProfiler *profiler;
- GError *error;
-
- /* Template Widgets */
- SysprofVisualizersFrame *visualizers;
- GtkStack *pages;
- SysprofDetailsPage *details;
- GtkStack *stack;
- SysprofProfilerAssistant *assistant;
- SysprofRecordingStateView *recording_view;
- SysprofFailedStateView *failed_view;
-
- SysprofCaptureFlags flags;
-} SysprofDisplayPrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofDisplay, sysprof_display, GTK_TYPE_WIDGET)
-
-enum {
- PROP_0,
- PROP_CAN_REPLAY,
- PROP_CAN_SAVE,
- PROP_RECORDING,
- PROP_TITLE,
- PROP_VISIBLE_PAGE,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-static void
-update_title_child_property (SysprofDisplay *self)
-{
- GtkWidget *parent;
-
- g_assert (SYSPROF_IS_DISPLAY (self));
-
- if ((parent = gtk_widget_get_parent (GTK_WIDGET (self))) && GTK_IS_NOTEBOOK (parent))
- {
- g_autofree gchar *title = sysprof_display_dup_title (self);
- gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (parent), GTK_WIDGET (self), title);
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
-}
-
-static void
-sysprof_display_profiler_failed_cb (SysprofDisplay *self,
- const GError *error,
- SysprofProfiler *profiler)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (error != NULL);
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- g_clear_object (&priv->profiler);
-
- /* Save the error for future use */
- g_clear_error (&priv->error);
- priv->error = g_error_copy (error);
-
- gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->failed_view));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RECORDING]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]);
-}
-
-static void
-sysprof_display_profiler_stopped_cb (SysprofDisplay *self,
- SysprofProfiler *profiler)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- SysprofCaptureWriter *writer;
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- if ((writer = sysprof_profiler_get_writer (profiler)))
- {
- g_autoptr(SysprofCaptureReader) reader = NULL;
- g_autoptr(GError) error = NULL;
-
- if (!(reader = sysprof_capture_writer_create_reader_with_error (writer, &error)))
- {
- g_warning ("Failed to create capture creader: %s\n", error->message);
- gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->failed_view));
- goto notify;
- }
-
- sysprof_display_load_async (self,
- reader,
- NULL, NULL, NULL);
- gtk_stack_set_visible_child_name (priv->stack, "view");
- }
-
-notify:
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RECORDING]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
-}
-
-static void
-sysprof_display_set_profiler (SysprofDisplay *self,
- SysprofProfiler *profiler)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- if (g_set_object (&priv->profiler, profiler))
- {
- sysprof_recording_state_view_set_profiler (priv->recording_view, profiler);
- gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->recording_view));
-
- g_signal_connect_object (profiler,
- "stopped",
- G_CALLBACK (sysprof_display_profiler_stopped_cb),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (profiler,
- "failed",
- G_CALLBACK (sysprof_display_profiler_failed_cb),
- self,
- G_CONNECT_SWAPPED);
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RECORDING]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
-}
-
-static void
-sysprof_display_start_recording_cb (SysprofDisplay *self,
- SysprofProfiler *profiler,
- SysprofProfilerAssistant *assistant)
-{
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
- g_assert (!assistant || SYSPROF_IS_PROFILER_ASSISTANT (assistant));
- g_assert (sysprof_display_is_empty (self));
-
- sysprof_display_set_profiler (self, profiler);
- sysprof_profiler_start (profiler);
-}
-
-static gboolean
-sysprof_display_get_is_recording (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_assert (SYSPROF_IS_DISPLAY (self));
-
- return GTK_WIDGET (priv->recording_view) == gtk_stack_get_visible_child (priv->stack);
-}
-
-gchar *
-sysprof_display_dup_title (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), NULL);
-
- if (priv->error)
- return g_strdup (_("Recording Failed"));
-
- if (priv->profiler != NULL)
- {
- if (sysprof_profiler_get_is_running (priv->profiler))
- return g_strdup (_("Recording…"));
- }
-
- if (priv->file != NULL)
- return g_file_get_basename (priv->file);
-
- if (priv->reader != NULL)
- {
- g_autoptr(GDateTime) dt = NULL;
- const gchar *filename;
- const gchar *capture_time;
-
- if ((filename = sysprof_capture_reader_get_filename (priv->reader)))
- return g_path_get_basename (filename);
-
- /* This recording is not yet on disk, but the time it was recorded
- * is much more useful than "New Recording".
- */
- capture_time = sysprof_capture_reader_get_time (priv->reader);
-
- if ((dt = g_date_time_new_from_iso8601 (capture_time, NULL)))
- {
- g_autoptr(GDateTime) local = g_date_time_to_local (dt);
- g_autofree gchar *formatted = NULL;
-
- if (local != NULL)
- formatted = g_date_time_format (local, "%X");
- else
- formatted = g_date_time_format (dt, "%X");
-
- /* translators: %s is replaced with locale specific time of recording */
- return g_strdup_printf (_("Recording at %s"), formatted);
- }
- }
-
- return g_strdup (_("New Recording"));
-}
-
-/**
- * sysprof_display_new:
- *
- * Create a new #SysprofDisplay.
- *
- * Returns: (transfer full): a newly created #SysprofDisplay
- */
-GtkWidget *
-sysprof_display_new (void)
-{
- return g_object_new (SYSPROF_TYPE_DISPLAY, NULL);
-}
-
-static void
-sysprof_display_notify_selection_cb (SysprofDisplay *self,
- GParamSpec *pspec,
- SysprofVisualizersFrame *visualizers)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- SysprofSelection *selection;
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (SYSPROF_IS_VISUALIZERS_FRAME (visualizers));
-
- g_clear_pointer (&priv->filter, sysprof_capture_condition_unref);
-
- if ((selection = sysprof_visualizers_frame_get_selection (visualizers)))
- {
- SysprofCaptureCondition *cond = NULL;
- guint n_ranges = sysprof_selection_get_n_ranges (selection);
-
- for (guint i = 0; i < n_ranges; i++)
- {
- SysprofCaptureCondition *c;
- gint64 begin, end;
-
- sysprof_selection_get_nth_range (selection, i, &begin, &end);
- c = sysprof_capture_condition_new_where_time_between (begin, end);
-
- if (cond == NULL)
- cond = c;
- else
- cond = sysprof_capture_condition_new_or (cond, c);
- }
-
- priv->filter = cond;
-
- /* Opportunistically load pages */
- if (priv->reader != NULL)
- {
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (priv->pages));
- child;
- child = gtk_widget_get_next_sibling (child))
- {
- if (SYSPROF_IS_PAGE (child))
- sysprof_page_load_async (SYSPROF_PAGE (child),
- priv->reader,
- selection,
- priv->filter,
- NULL, NULL, NULL);
- }
- }
- }
-}
-
-static void
-change_page_cb (GSimpleAction *action,
- GVariant *param,
- gpointer user_data)
-{
- SysprofDisplay *self = user_data;
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (param != NULL);
-
- if (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING))
- {
- const gchar *str = g_variant_get_string (param, NULL);
-
- gtk_stack_set_visible_child_name (priv->pages, str);
-
- if (g_str_equal (str, "details"))
- sysprof_visualizers_frame_unselect_row (priv->visualizers);
- }
-}
-
-static void
-stop_recording_cb (GSimpleAction *action,
- GVariant *param,
- gpointer user_data)
-{
- SysprofDisplay *self = user_data;
-
- g_assert (G_IS_SIMPLE_ACTION (action));
- g_assert (SYSPROF_IS_DISPLAY (self));
-
- sysprof_display_stop_recording (self);
-}
-
-static void
-sysprof_display_dispose (GObject *object)
-{
- SysprofDisplay *self = (SysprofDisplay *)object;
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- if (priv->stack)
- {
- gtk_widget_unparent (GTK_WIDGET (priv->stack));
- priv->stack = NULL;
- }
-
- g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
- g_clear_pointer (&priv->filter, sysprof_capture_condition_unref);
-
- G_OBJECT_CLASS (sysprof_display_parent_class)->dispose (object);
-}
-
-static void
-sysprof_display_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofDisplay *self = SYSPROF_DISPLAY (object);
-
- switch (prop_id)
- {
- case PROP_CAN_REPLAY:
- g_value_set_boolean (value, sysprof_display_get_can_replay (self));
- break;
-
- case PROP_CAN_SAVE:
- g_value_set_boolean (value, sysprof_display_get_can_save (self));
- break;
-
- case PROP_RECORDING:
- g_value_set_boolean (value, sysprof_display_get_is_recording (self));
- break;
-
- case PROP_TITLE:
- g_value_take_string (value, sysprof_display_dup_title (self));
- break;
-
- case PROP_VISIBLE_PAGE:
- g_value_set_object (value, sysprof_display_get_visible_page (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_display_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofDisplay *self = SYSPROF_DISPLAY (object);
-
- switch (prop_id)
- {
- case PROP_VISIBLE_PAGE:
- sysprof_display_set_visible_page (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_display_class_init (SysprofDisplayClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = sysprof_display_dispose;
- object_class->get_property = sysprof_display_get_property;
- object_class->set_property = sysprof_display_set_property;
-
- sysprof_theme_manager_register_resource (sysprof_theme_manager_get_default (),
- NULL,
- NULL,
- "/org/gnome/sysprof/css/SysprofDisplay-shared.css");
-
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-display.ui");
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
- gtk_widget_class_set_css_name (widget_class, "SysprofDisplay");
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, assistant);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, details);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, failed_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, pages);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, recording_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, stack);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay, visualizers);
-
- properties [PROP_CAN_REPLAY] =
- g_param_spec_boolean ("can-replay",
- "Can Replay",
- "If the capture contains enough information to re-run the recording",
- FALSE,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CAN_SAVE] =
- g_param_spec_boolean ("can-save",
- "Can Save",
- "If the display can save a recording",
- FALSE,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_RECORDING] =
- g_param_spec_boolean ("recording",
- "Recording",
- "If the display is in recording state",
- FALSE,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_TITLE] =
- g_param_spec_string ("title",
- "Title",
- "The title of the display",
- NULL,
- (G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_VISIBLE_PAGE] =
- g_param_spec_object ("visible-page",
- "Visible Page",
- "Visible Page",
- SYSPROF_TYPE_PAGE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- g_type_ensure (EGG_TYPE_PANED);
- g_type_ensure (SYSPROF_TYPE_DETAILS_PAGE);
- g_type_ensure (SYSPROF_TYPE_FAILED_STATE_VIEW);
- g_type_ensure (SYSPROF_TYPE_PROFILER_ASSISTANT);
- g_type_ensure (SYSPROF_TYPE_RECORDING_STATE_VIEW);
- g_type_ensure (SYSPROF_TYPE_VISUALIZERS_FRAME);
-}
-
-static void
-sysprof_display_init (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- g_autoptr(GSimpleActionGroup) group = g_simple_action_group_new ();
- static GActionEntry entries[] = {
- { "page", change_page_cb, "s" },
- { "stop-recording", stop_recording_cb },
- };
- g_autoptr(GPropertyAction) page = NULL;
-
- gtk_widget_init_template (GTK_WIDGET (self));
-
- g_signal_connect_object (priv->assistant,
- "start-recording",
- G_CALLBACK (sysprof_display_start_recording_cb),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->visualizers,
- "notify::selection",
- G_CALLBACK (sysprof_display_notify_selection_cb),
- self,
- G_CONNECT_SWAPPED);
-
- page = g_property_action_new ("page", priv->pages, "visible-child-name");
- g_action_map_add_action_entries (G_ACTION_MAP (group),
- entries,
- G_N_ELEMENTS (entries),
- self);
- gtk_widget_insert_action_group (GTK_WIDGET (self), "display", G_ACTION_GROUP (group));
-}
-
-void
-sysprof_display_add_group (SysprofDisplay *self,
- SysprofVisualizerGroup *group)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (group));
-
- if (priv->reader != NULL)
- _sysprof_visualizer_group_set_reader (group, priv->reader);
-
- sysprof_visualizers_frame_add_group (priv->visualizers, group);
-}
-
-void
-sysprof_display_add_page (SysprofDisplay *self,
- SysprofPage *page)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- SysprofSelection *selection;
- const gchar *title;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (SYSPROF_IS_PAGE (page));
-
- title = sysprof_page_get_title (page);
- gtk_stack_add_titled (priv->pages, GTK_WIDGET (page), NULL, title);
-
- selection = sysprof_visualizers_frame_get_selection (priv->visualizers);
-
- sysprof_page_set_size_group (page,
- sysprof_visualizers_frame_get_size_group (priv->visualizers));
-
- sysprof_page_set_hadjustment (page,
- sysprof_visualizers_frame_get_hadjustment (priv->visualizers));
-
- if (priv->reader != NULL)
- sysprof_page_load_async (page,
- priv->reader,
- selection,
- priv->filter,
- NULL, NULL, NULL);
-}
-
-SysprofPage *
-sysprof_display_get_visible_page (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- GtkWidget *visible_page;
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), NULL);
-
- visible_page = gtk_stack_get_visible_child (priv->pages);
-
- if (SYSPROF_IS_PAGE (visible_page))
- return SYSPROF_PAGE (visible_page);
-
- return NULL;
-}
-
-void
-sysprof_display_set_visible_page (SysprofDisplay *self,
- SysprofPage *page)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (SYSPROF_IS_PAGE (page));
-
- gtk_stack_set_visible_child (priv->pages, GTK_WIDGET (page));
-}
-
-static void
-sysprof_display_present_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofAid *aid = (SysprofAid *)object;
- g_autoptr(GTask) task = user_data;
- g_autoptr(GError) error = NULL;
- gatomicrefcount *n_active;
-
- g_assert (SYSPROF_IS_AID (aid));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- if (!sysprof_aid_present_finish (aid, result, &error))
- {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
- g_warning ("Failed to present aid %s: %s", G_OBJECT_TYPE_NAME (aid), error->message);
- }
-
- n_active = g_task_get_task_data (task);
-
- if (g_atomic_ref_count_dec (n_active))
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_display_present_async (SysprofDisplay *self,
- SysprofCaptureReader *reader,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(GPtrArray) aids = NULL;
- g_autoptr(GTask) task = NULL;
- g_autofree gatomicrefcount *aids_len = NULL;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- aids = g_ptr_array_new_with_free_func (g_object_unref);
- g_ptr_array_add (aids, sysprof_battery_aid_new ());
- g_ptr_array_add (aids, sysprof_counters_aid_new ());
- g_ptr_array_add (aids, sysprof_cpu_aid_new ());
- g_ptr_array_add (aids, sysprof_callgraph_aid_new ());
- g_ptr_array_add (aids, sysprof_diskstat_aid_new ());
- g_ptr_array_add (aids, sysprof_logs_aid_new ());
- g_ptr_array_add (aids, sysprof_marks_aid_new ());
- g_ptr_array_add (aids, sysprof_memory_aid_new ());
- g_ptr_array_add (aids, sysprof_memprof_aid_new ());
- g_ptr_array_add (aids, sysprof_netdev_aid_new ());
- g_ptr_array_add (aids, sysprof_rapl_aid_new ());
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_display_present_async);
-
- if (aids->len == 0)
- {
- g_task_return_boolean (task, TRUE);
- return;
- }
-
- aids_len = g_new (gatomicrefcount, 1);
- g_atomic_ref_count_init(aids_len);
- *aids_len = aids->len;
-
- g_task_set_task_data (task, g_steal_pointer (&aids_len), g_free);
-
- for (guint i = 0; i < aids->len; i++)
- {
- SysprofAid *aid = g_ptr_array_index (aids, i);
-
- sysprof_aid_present_async (aid,
- reader,
- self,
- cancellable,
- sysprof_display_present_cb,
- g_object_ref (task));
- }
-}
-
-static gboolean
-sysprof_display_present_finish (SysprofDisplay *self,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_display_scan_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- SysprofDisplay *self = source_object;
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- SysprofCaptureReader *reader = task_data;
- g_autoptr(GHashTable) mark_stats = NULL;
- g_autoptr(GArray) marks = NULL;
- SysprofCaptureFrame frame;
- SysprofCaptureStat st = {{0}};
- SysprofCaptureFlags flags = 0;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (reader != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- /* Scan the reader until the end so that we know we have gotten
- * all of the timing data loaded into the underlying reader.
- */
-
- mark_stats = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- marks = g_array_new (FALSE, FALSE, sizeof (SysprofMarkStat));
-
- while (sysprof_capture_reader_peek_frame (reader, &frame))
- {
- if (frame.type < G_N_ELEMENTS (st.frame_count))
- st.frame_count[frame.type]++;
-
- if (frame.type == SYSPROF_CAPTURE_FRAME_METADATA)
- {
- const SysprofCaptureMetadata *meta;
-
- if ((meta = sysprof_capture_reader_read_metadata (reader)))
- {
- if (g_strcmp0 (meta->id, "local-profiler") == 0)
- flags |= SYSPROF_CAPTURE_FLAGS_CAN_REPLAY;
- }
- }
- else if (frame.type == SYSPROF_CAPTURE_FRAME_MARK)
- {
- const SysprofCaptureMark *mark;
-
- if ((mark = sysprof_capture_reader_read_mark (reader)))
- {
- SysprofMarkStat *mstat;
- gchar name[152];
- gpointer idx;
-
- g_snprintf (name, sizeof name, "%s:%s", mark->group, mark->name);
-
- if (!(idx = g_hash_table_lookup (mark_stats, name)))
- {
- SysprofMarkStat empty = {{0}};
-
- g_strlcpy (empty.name, name, sizeof empty.name);
- g_array_append_val (marks, empty);
- idx = GUINT_TO_POINTER (marks->len);
- g_hash_table_insert (mark_stats, g_strdup (name), idx);
- }
-
- mstat = &g_array_index (marks, SysprofMarkStat, GPOINTER_TO_UINT (idx) - 1);
-
- if (mark->duration > 0)
- {
- if (mstat->min == 0 || mark->duration < mstat->min)
- mstat->min = mark->duration;
- }
-
- if (mark->duration > mstat->max)
- mstat->max = mark->duration;
-
- if (mark->duration > 0)
- {
- mstat->avg += mark->duration;
- mstat->avg_count++;
- }
-
- mstat->count++;
- }
- }
- else
- {
- sysprof_capture_reader_skip (reader);
- }
- }
-
- {
- GHashTableIter iter;
- gpointer k,v;
-
- g_hash_table_iter_init (&iter, mark_stats);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- guint idx = GPOINTER_TO_UINT (v) - 1;
- SysprofMarkStat *mstat = &g_array_index (marks, SysprofMarkStat, idx);
-
- if (mstat->avg_count > 0 && mstat->avg > 0)
- mstat->avg /= mstat->avg_count;
-
-#if 0
- g_print ("%s: count=%ld avg=%ld min=%ld max=%ld\n",
- (gchar*)k,
- ((SysprofMarkStat *)v)->count,
- ((SysprofMarkStat *)v)->avg,
- ((SysprofMarkStat *)v)->min,
- ((SysprofMarkStat *)v)->max);
-#endif
- }
- }
-
- g_object_set_data_full (G_OBJECT (task),
- "MARK_STAT",
- g_steal_pointer (&marks),
- (GDestroyNotify) g_array_unref);
-
- g_atomic_int_set (&priv->flags, flags);
- sysprof_capture_reader_reset (reader);
- sysprof_capture_reader_set_stat (reader, &st);
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_display_scan_async (SysprofDisplay *self,
- SysprofCaptureReader *reader,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(GTask) task = NULL;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_display_scan_async);
- g_task_set_task_data (task,
- sysprof_capture_reader_ref (reader),
- (GDestroyNotify) sysprof_capture_reader_unref);
- g_task_run_in_thread (task, sysprof_display_scan_worker);
-}
-
-static gboolean
-sysprof_display_scan_finish (SysprofDisplay *self,
- GAsyncResult *result,
- GError **error)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- GArray *marks;
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- if ((marks = g_object_get_data (G_OBJECT (result), "MARK_STAT")))
- sysprof_details_page_add_marks (priv->details,
- (const SysprofMarkStat *)(gpointer)marks->data,
- marks->len);
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_display_load_present_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofDisplay *self = (SysprofDisplay *)object;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- if (!sysprof_display_present_finish (self, result, &error))
- g_warning ("Error presenting: %s", error->message);
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_display_load_frame_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofVisualizersFrame *frame = (SysprofVisualizersFrame *)object;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
- SysprofCaptureReader *reader;
- SysprofDisplay *self;
- GCancellable *cancellable;
-
- g_assert (SYSPROF_IS_VISUALIZERS_FRAME (frame));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- self = g_task_get_source_object (task);
- reader = g_task_get_task_data (task);
- cancellable = g_task_get_cancellable (task);
-
- if (!sysprof_visualizers_frame_load_finish (frame, result, &error))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- sysprof_display_present_async (self,
- reader,
- cancellable,
- sysprof_display_load_present_cb,
- g_steal_pointer (&task));
-}
-
-static void
-sysprof_display_load_scan_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofDisplay *self = (SysprofDisplay *)object;
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- g_autoptr(GTask) task = user_data;
- g_autoptr(GError) error = NULL;
- SysprofCaptureReader *reader;
- SysprofSelection *selection;
- GCancellable *cancellable;
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- reader = g_task_get_task_data (task);
- cancellable = g_task_get_cancellable (task);
-
- if (!sysprof_display_scan_finish (self, result, &error))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- sysprof_visualizers_frame_load_async (priv->visualizers,
- reader,
- cancellable,
- sysprof_display_load_frame_cb,
- g_steal_pointer (&task));
-
- selection = sysprof_visualizers_frame_get_selection (priv->visualizers);
-
- sysprof_details_page_set_reader (priv->details, reader);
-
- /* Opportunistically load pages */
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (priv->pages));
- child;
- child = gtk_widget_get_next_sibling (child))
- {
- if (SYSPROF_IS_PAGE (child))
- sysprof_page_load_async (SYSPROF_PAGE (child),
- reader,
- selection,
- priv->filter,
- NULL, NULL, NULL);
- }
-
- gtk_stack_set_visible_child_name (priv->stack, "view");
-}
-
-void
-sysprof_display_load_async (SysprofDisplay *self,
- SysprofCaptureReader *reader,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- g_autoptr(GTask) task = NULL;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- if (priv->reader != reader)
- {
- g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
- priv->reader = sysprof_capture_reader_ref (reader);
- }
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_display_load_async);
- g_task_set_task_data (task,
- sysprof_capture_reader_ref (reader),
- (GDestroyNotify) sysprof_capture_reader_unref);
-
- /* First scan the reader for any sort of data we care about before
- * we notify aids to load content. That allows us to ensure we have
- * proper timing data for the consumers.
- */
- sysprof_display_scan_async (self,
- reader,
- cancellable,
- sysprof_display_load_scan_cb,
- g_steal_pointer (&task));
-}
-
-gboolean
-sysprof_display_load_finish (SysprofDisplay *self,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-SysprofZoomManager *
-sysprof_display_get_zoom_manager (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), NULL);
-
- return sysprof_visualizers_frame_get_zoom_manager (priv->visualizers);
-}
-
-/**
- * sysprof_display_is_empty:
- *
- * Checks if any content is or will be loaded into @self.
- *
- * Returns: %TRUE if the tab is unperterbed.
- *
- * Since: 3.34
- */
-gboolean
-sysprof_display_is_empty (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE);
-
- return priv->file == NULL &&
- priv->profiler == NULL &&
- gtk_stack_get_visible_child (priv->stack) == GTK_WIDGET (priv->assistant) &&
- NULL == priv->reader;
-}
-
-void
-sysprof_display_open (SysprofDisplay *self,
- GFile *file)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- g_autoptr(SysprofCaptureReader) reader = NULL;
- g_autoptr(GError) error = NULL;
- g_autofree gchar *path = NULL;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (G_IS_FILE (file));
- g_return_if_fail (g_file_is_native (file));
- g_return_if_fail (sysprof_display_is_empty (self));
-
- path = g_file_get_path (file);
-
- /* If the file is executable, just set the path to the binary
- * in the profiler assistant.
- */
- if (g_file_test (path, G_FILE_TEST_IS_EXECUTABLE))
- {
- sysprof_profiler_assistant_set_executable (priv->assistant, path);
- return;
- }
-
- g_set_object (&priv->file, file);
-
- if (!(reader = sysprof_capture_reader_new_with_error (path, &error)))
- {
- GtkWidget *dialog;
- GtkWidget *window;
-
- g_warning ("Failed to open capture: %s", error->message);
-
- window = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_WINDOW);
- dialog = gtk_message_dialog_new (NULL,
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_CLOSE,
- "%s",
- _("The recording could not be opened"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- "%s",
- error->message);
- g_signal_connect (dialog,
- "response",
- G_CALLBACK (gtk_window_destroy),
- NULL);
- gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
- gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
- gtk_window_present (GTK_WINDOW (dialog));
-
- _sysprof_display_destroy (self);
-
- return;
- }
-
- /* Jump right to the "view" page to avoid a quick view of the
- * assistants page when loading.
- */
- if (g_strcmp0 ("assistant", gtk_stack_get_visible_child_name (priv->stack)) == 0)
- gtk_stack_set_visible_child_name (priv->stack, "view");
-
- sysprof_display_load_async (self, reader, NULL, NULL, NULL);
- update_title_child_property (self);
-}
-
-gboolean
-sysprof_display_get_can_save (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE);
-
- return priv->reader != NULL;
-}
-
-void
-sysprof_display_stop_recording (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
-
- if (priv->profiler != NULL)
- sysprof_profiler_stop (priv->profiler);
-}
-
-void
-_sysprof_display_focus_record (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
-
- _sysprof_profiler_assistant_focus_record (priv->assistant);
-}
-
-gboolean
-sysprof_display_get_can_replay (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), FALSE);
-
- return !sysprof_display_is_empty (self) &&
- priv->reader != NULL &&
- !!(priv->flags & SYSPROF_CAPTURE_FLAGS_CAN_REPLAY);
-}
-
-/**
- * sysprof_display_replay:
- * @self: a #SysprofDisplay
- *
- * Gets a new display that will re-run the previous recording that is being
- * viewed. This requires a capture file which contains enough information to
- * replay the operation.
- *
- * Returns: (nullable) (transfer full): a #SysprofDisplay or %NULL
- *
- * Since: 3.34
- */
-SysprofDisplay *
-sysprof_display_replay (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- g_autoptr(SysprofProfiler) profiler = NULL;
- SysprofDisplay *copy;
-
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), NULL);
- g_return_val_if_fail (priv->reader != NULL, NULL);
-
- profiler = sysprof_local_profiler_new_replay (priv->reader);
- g_return_val_if_fail (profiler != NULL, NULL);
- g_return_val_if_fail (SYSPROF_IS_LOCAL_PROFILER (profiler), NULL);
-
- copy = g_object_new (SYSPROF_TYPE_DISPLAY, NULL);
- sysprof_display_set_profiler (copy, profiler);
- sysprof_profiler_start (profiler);
-
- return g_steal_pointer (©);
-}
-
-GtkWidget *
-sysprof_display_new_for_profiler (SysprofProfiler *profiler)
-{
- SysprofDisplay *self;
-
- g_return_val_if_fail (SYSPROF_IS_PROFILER (profiler), NULL);
-
- self = g_object_new (SYSPROF_TYPE_DISPLAY, NULL);
- sysprof_display_set_profiler (self, profiler);
-
- return GTK_WIDGET (g_steal_pointer (&self));
-}
-
-static void
-on_save_response_cb (SysprofDisplay *self,
- int res,
- GtkFileChooserNative *chooser)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- g_autoptr(GFile) file = NULL;
-
- g_assert (SYSPROF_IS_DISPLAY (self));
- g_assert (GTK_IS_FILE_CHOOSER_NATIVE (chooser));
-
- switch (res)
- {
- case GTK_RESPONSE_ACCEPT:
- file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser));
-
- if (g_file_is_native (file))
- {
- g_autofree gchar *path = g_file_get_path (file);
- g_autoptr(GError) error = NULL;
-
- if (!sysprof_capture_reader_save_as_with_error (priv->reader, path, &error))
- {
- GtkWidget *msg;
- GtkNative *root;
-
- root = gtk_widget_get_native (GTK_WIDGET (self));
- msg = gtk_message_dialog_new (GTK_WINDOW (root),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("Failed to save recording: %s"),
- error->message);
- gtk_window_present (GTK_WINDOW (msg));
- g_signal_connect (msg, "response", G_CALLBACK (gtk_window_destroy), NULL);
- }
- }
- else
- {
- g_autofree char *uri = g_file_get_uri (file);
- g_warning ("%s is not native, cannot open", uri);
- }
-
- break;
-
- default:
- break;
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
- gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
-}
-
-void
-sysprof_display_save (SysprofDisplay *self)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- GtkFileChooserNative *native;
- GtkNative *root;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (priv->reader != NULL);
-
- root = gtk_widget_get_native (GTK_WIDGET (self));
- native = gtk_file_chooser_native_new (_("Save Recording"),
- GTK_WINDOW (root),
- GTK_FILE_CHOOSER_ACTION_SAVE,
- _("Save"),
- _("Cancel"));
- gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER (native), TRUE);
- gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (native), "capture.syscap");
-
- g_signal_connect_object (native,
- "response",
- G_CALLBACK (on_save_response_cb),
- self,
- G_CONNECT_SWAPPED);
-
- gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
-}
-
-void
-_sysprof_display_reload_page (SysprofDisplay *self,
- SysprofPage *page)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- SysprofSelection *selection;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
- g_return_if_fail (SYSPROF_IS_PAGE (page));
- g_return_if_fail (priv->reader != NULL);
-
- selection = sysprof_visualizers_frame_get_selection (priv->visualizers);
-
- sysprof_page_load_async (page,
- priv->reader,
- selection,
- priv->filter,
- NULL, NULL, NULL);
-}
-
-void
-sysprof_display_add_to_selection (SysprofDisplay *self,
- gint64 begin_time,
- gint64 end_time)
-{
- SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self);
- SysprofSelection *selection;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
-
- selection = sysprof_visualizers_frame_get_selection (priv->visualizers);
- sysprof_selection_select_range (selection, begin_time, end_time);
-}
-
-void
-_sysprof_display_destroy (SysprofDisplay *self)
-{
- GtkWidget *parent;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (self));
-
- if ((parent = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_NOTEBOOK)))
- gtk_notebook_remove_page (GTK_NOTEBOOK (parent),
- gtk_notebook_page_num (GTK_NOTEBOOK (parent), GTK_WIDGET (self)));
-}
diff --git a/src/libsysprof-ui/sysprof-display.h b/src/libsysprof-ui/sysprof-display.h
deleted file mode 100644
index 16cd9f55..00000000
--- a/src/libsysprof-ui/sysprof-display.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* sysprof-display.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-#include
-
-#include "sysprof-page.h"
-#include "sysprof-visualizer-group.h"
-#include "sysprof-zoom-manager.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_DISPLAY (sysprof_display_get_type())
-
-SYSPROF_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE (SysprofDisplay, sysprof_display, SYSPROF, DISPLAY, GtkWidget)
-
-struct _SysprofDisplayClass
-{
- GtkWidgetClass parent_class;
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-SYSPROF_AVAILABLE_IN_ALL
-GtkWidget *sysprof_display_new (void);
-SYSPROF_AVAILABLE_IN_ALL
-GtkWidget *sysprof_display_new_for_profiler (SysprofProfiler *profiler);
-SYSPROF_AVAILABLE_IN_ALL
-char *sysprof_display_dup_title (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofProfiler *sysprof_display_get_profiler (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_add_group (SysprofDisplay *self,
- SysprofVisualizerGroup *group);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_add_page (SysprofDisplay *self,
- SysprofPage *page);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofPage *sysprof_display_get_visible_page (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_set_visible_page (SysprofDisplay *self,
- SysprofPage *page);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofZoomManager *sysprof_display_get_zoom_manager (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_load_async (SysprofDisplay *self,
- SysprofCaptureReader *reader,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_display_load_finish (SysprofDisplay *self,
- GAsyncResult *result,
- GError **error);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_display_is_empty (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_open (SysprofDisplay *self,
- GFile *file);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_save (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_display_get_can_save (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_display_stop_recording (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_display_get_can_replay (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofDisplay *sysprof_display_replay (SysprofDisplay *self);
-SYSPROF_AVAILABLE_IN_3_38
-void sysprof_display_add_to_selection (SysprofDisplay *self,
- gint64 begin_time,
- gint64 end_time);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-display.ui b/src/libsysprof-ui/sysprof-display.ui
deleted file mode 100644
index 61fceb7a..00000000
--- a/src/libsysprof-ui/sysprof-display.ui
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
-
-
- 0
- 0
-
-
- assistant
-
-
-
-
-
-
-
-
- view
-
-
- vertical
-
-
- false
-
-
-
-
- 0
- 0
- true
-
-
- Details
- details
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- record
-
-
-
-
-
-
-
-
- failed
-
-
-
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-duplex-visualizer.c b/src/libsysprof-ui/sysprof-duplex-visualizer.c
deleted file mode 100644
index e9289a62..00000000
--- a/src/libsysprof-ui/sysprof-duplex-visualizer.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/* sysprof-duplex-visualizer.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-duplex-visualizer"
-
-#include "config.h"
-
-#include "pointcache.h"
-#include "sysprof-duplex-visualizer.h"
-
-#define LABEL_HEIGHT_PX 10
-
-struct _SysprofDuplexVisualizer
-{
- SysprofVisualizer parent_instance;
-
- gint64 begin_time;
- gint64 duration;
-
- guint rx_counter;
- guint tx_counter;
-
- GdkRGBA rx_rgba;
- GdkRGBA tx_rgba;
-
- gchar *rx_label;
- gchar *tx_label;
-
- PointCache *cache;
-
- guint rx_rgba_set : 1;
- guint tx_rgba_set : 1;
- guint use_diff : 1;
-};
-
-typedef struct
-{
- PointCache *cache;
-
- gint64 begin_time;
- gint64 duration;
-
- gint64 max_change;
-
- /* Last value to convert to rate of change */
- gint64 last_rx_val;
- gint64 last_tx_val;
-
- /* Counter IDs */
- guint rx;
- guint tx;
-
- /* Do we need to subtract previous value */
- guint use_diff : 1;
-} Collect;
-
-G_DEFINE_TYPE (SysprofDuplexVisualizer, sysprof_duplex_visualizer, SYSPROF_TYPE_VISUALIZER)
-
-static bool
-collect_ranges_cb (const SysprofCaptureFrame *frame,
- gpointer data)
-{
- Collect *state = data;
-
- g_assert (frame != NULL);
- g_assert (state != NULL);
- g_assert (state->cache != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
- {
- const SysprofCaptureCounterSet *set = (gconstpointer)frame;
-
- for (guint i = 0; i < set->n_values; i++)
- {
- const SysprofCaptureCounterValues *values = &set->values[i];
-
- for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
- {
- gint64 v64 = values->values[j].v64;
- guint id = values->ids[j];
- gint64 max_change = 0;
-
- if (id == 0)
- break;
-
- if (id == state->rx)
- {
- if (state->last_rx_val != G_MININT64)
- max_change = v64 - state->last_rx_val;
- state->last_rx_val = v64;
- }
- else if (id == state->tx)
- {
- if (state->last_tx_val != G_MININT64)
- max_change = v64 - state->last_tx_val;
- state->last_tx_val = v64;
- }
- else
- {
- continue;
- }
-
- if (max_change > state->max_change)
- state->max_change = max_change;
- }
- }
- }
-
- return TRUE;
-}
-
-static bool
-collect_values_cb (const SysprofCaptureFrame *frame,
- gpointer data)
-{
- Collect *state = data;
-
- g_assert (frame != NULL);
- g_assert (state != NULL);
- g_assert (state->cache != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
- {
- const SysprofCaptureCounterSet *set = (gconstpointer)frame;
- gdouble x = (frame->time - state->begin_time) / (gdouble)state->duration;
-
- for (guint i = 0; i < set->n_values; i++)
- {
- const SysprofCaptureCounterValues *values = &set->values[i];
-
- for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
- {
- gint64 v64 = values->values[j].v64;
- guint id = values->ids[j];
- gint64 val = v64;
- gdouble y = 0.5;
-
- if (id == 0)
- break;
-
- if (id == state->rx)
- {
- if (state->use_diff)
- {
- if (state->last_rx_val == G_MININT64)
- val = 0;
- else
- val -= state->last_rx_val;
- }
-
- /* RX goes upward from half point */
- if (state->max_change != 0)
- y += (gdouble)val / (gdouble)state->max_change / 2.0;
-
- state->last_rx_val = v64;
- }
- else if (id == state->tx)
- {
- if (state->use_diff)
- {
- if (state->last_tx_val == G_MININT64)
- val = 0;
- else
- val -= state->last_tx_val;
- }
-
- /* TX goes downward from half point */
- if (state->max_change != 0)
- y -= (gdouble)val / (gdouble)state->max_change / 2.0;
-
- state->last_tx_val = v64;
- }
- else
- {
- continue;
- }
-
- point_cache_add_point_to_set (state->cache, id, x, y);
- }
- }
- }
-
- return TRUE;
-}
-
-static void
-sysprof_duplex_visualizer_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- SysprofCaptureCursor *cursor = task_data;
- SysprofDuplexVisualizer *self = source_object;
- Collect state = {0};
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
- g_assert (cursor != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- state.cache = point_cache_new ();
- state.begin_time = self->begin_time;
- state.duration = self->duration;
- state.rx = g_atomic_int_get (&self->rx_counter);
- state.tx = g_atomic_int_get (&self->tx_counter);
- state.last_rx_val = G_MININT64;
- state.last_tx_val = G_MININT64;
- state.max_change = 0;
- state.use_diff = self->use_diff;
-
- point_cache_add_set (state.cache, state.rx);
- point_cache_add_set (state.cache, state.tx);
-
- sysprof_capture_cursor_foreach (cursor, collect_ranges_cb, &state);
- sysprof_capture_cursor_reset (cursor);
-
- /* Give just a bit of overhead */
- state.max_change *= 1.1;
-
- /* Reset for calculations */
- state.last_rx_val = G_MININT64;
- state.last_tx_val = G_MININT64;
-
- sysprof_capture_cursor_foreach (cursor, collect_values_cb, &state);
-
- g_task_return_pointer (task,
- g_steal_pointer (&state.cache),
- (GDestroyNotify) point_cache_unref);
-}
-
-static void
-load_data_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)object;
- g_autoptr(PointCache) pc = NULL;
-
- g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
- g_assert (G_IS_TASK (result));
-
- if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
- {
- g_clear_pointer (&self->cache, point_cache_unref);
- self->cache = g_steal_pointer (&pc);
- gtk_widget_queue_draw (GTK_WIDGET (self));
- }
-}
-
-static void
-sysprof_duplex_visualizer_set_reader (SysprofVisualizer *visualizer,
- SysprofCaptureReader *reader)
-{
- SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)visualizer;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- SysprofCaptureCondition *c;
- guint counters[2];
-
- g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
- g_assert (reader != NULL);
-
- self->begin_time = sysprof_capture_reader_get_start_time (reader);
- self->duration = sysprof_capture_reader_get_end_time (reader)
- - sysprof_capture_reader_get_start_time (reader);
-
- counters[0] = self->rx_counter;
- counters[1] = self->tx_counter;
-
- cursor = sysprof_capture_cursor_new (reader);
- c = sysprof_capture_condition_new_where_counter_in (G_N_ELEMENTS (counters), counters);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
-
- task = g_task_new (self, NULL, load_data_cb, NULL);
- g_task_set_source_tag (task, sysprof_duplex_visualizer_set_reader);
- g_task_set_task_data (task,
- g_steal_pointer (&cursor),
- (GDestroyNotify)sysprof_capture_cursor_unref);
- g_task_run_in_thread (task, sysprof_duplex_visualizer_worker);
-}
-
-static void
-sysprof_duplex_visualizer_snapshot (GtkWidget *widget,
- GtkSnapshot *snapshot)
-{
- static const gdouble dashes[] = { 1.0, 2.0 };
- SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)widget;
- PangoFontDescription *font_desc;
- GtkStyleContext *style_context;
- PangoLayout *layout;
- cairo_t *cr;
- GtkAllocation alloc;
- GdkRGBA fg;
- guint mid;
-
- g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
- g_assert (snapshot != NULL);
-
- /* FIXME: This should all be drawn offscreen and then drawn to the snapshot
- * using GdkMemoryTexture so that we can avoid extra GPU uploads.
- */
-
- gtk_widget_get_allocation (widget, &alloc);
-
- mid = alloc.height / 2;
-
- GTK_WIDGET_CLASS (sysprof_duplex_visualizer_parent_class)->snapshot (widget, snapshot);
-
- cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
-
- style_context = gtk_widget_get_style_context (widget);
- gtk_style_context_get_color (style_context, &fg);
- fg.alpha *= 0.4;
-
- /* Draw our center line */
- cairo_save (cr);
- cairo_set_line_width (cr, 1.0);
- cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
- cairo_move_to (cr, 0, mid);
- cairo_line_to (cr, alloc.width, mid);
- gdk_cairo_set_source_rgba (cr, &fg);
- cairo_stroke (cr);
- cairo_restore (cr);
-
- if (self->cache != NULL)
- {
- g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
- const Point *fpoints;
- guint n_fpoints = 0;
-
- cairo_save (cr);
- cairo_set_line_width (cr, 1.0);
- if (self->rx_rgba_set)
- gdk_cairo_set_source_rgba (cr, &self->rx_rgba);
-
- fpoints = point_cache_get_points (self->cache, self->rx_counter, &n_fpoints);
-
- if (n_fpoints > 0)
- {
- GdkRGBA rgba = self->rx_rgba;
- gdouble last_x;
- gdouble last_y;
- guint p;
-
- points = g_realloc_n (points, n_fpoints, sizeof *points);
-
- sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
- (const SysprofVisualizerRelativePoint *)fpoints,
- n_fpoints,
- points,
- n_fpoints);
-
- /* Skip past data that we won't see anyway */
-#if 0
- for (p = 0; p < n_fpoints; p++)
- {
- if (points[p].x >= clip.x)
- break;
- }
-
- if (p >= n_fpoints)
- return;
-#endif
-
- /* But get at least one data point to anchor out of view */
- if (p > 0)
- p--;
-
- last_x = points[p].x;
- last_y = points[p].y;
-
- cairo_move_to (cr, last_x, mid);
- cairo_line_to (cr, last_x, last_y);
-
- for (guint i = p + 1; i < n_fpoints; i++)
- {
- cairo_curve_to (cr,
- last_x + ((points[i].x - last_x) / 2),
- last_y,
- last_x + ((points[i].x - last_x) / 2),
- points[i].y,
- points[i].x,
- points[i].y);
-
- last_x = points[i].x;
- last_y = points[i].y;
-
-#if 0
- if (points[i].x > clip.x + clip.width)
- break;
-#endif
- }
-
- cairo_line_to (cr, last_x, mid);
- cairo_close_path (cr);
- cairo_stroke_preserve (cr);
- rgba.alpha *= 0.5;
- gdk_cairo_set_source_rgba (cr, &rgba);
- cairo_fill (cr);
- }
-
- cairo_restore (cr);
-
- /* AND NOW Tx */
-
- cairo_save (cr);
- cairo_set_line_width (cr, 1.0);
- if (self->tx_rgba_set)
- gdk_cairo_set_source_rgba (cr, &self->tx_rgba);
-
- fpoints = point_cache_get_points (self->cache, self->tx_counter, &n_fpoints);
-
- if (n_fpoints > 0)
- {
- GdkRGBA rgba = self->tx_rgba;
- gdouble last_x;
- gdouble last_y;
- guint p;
-
- points = g_realloc_n (points, n_fpoints, sizeof *points);
-
- sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
- (const SysprofVisualizerRelativePoint *)fpoints,
- n_fpoints,
- points,
- n_fpoints);
-
-#if 0
- /* Skip past data that we won't see anyway */
- for (p = 0; p < n_fpoints; p++)
- {
- if (points[p].x >= clip.x)
- break;
- }
-
- if (p >= n_fpoints)
- return ret;
-#endif
-
- /* But get at least one data point to anchor out of view */
- if (p > 0)
- p--;
-
- last_x = points[p].x;
- last_y = points[p].y;
-
- cairo_move_to (cr, last_x, mid);
- cairo_line_to (cr, last_x, last_y);
-
- for (guint i = p + 1; i < n_fpoints; i++)
- {
- cairo_curve_to (cr,
- last_x + ((points[i].x - last_x) / 2),
- last_y,
- last_x + ((points[i].x - last_x) / 2),
- points[i].y,
- points[i].x,
- points[i].y);
-
- last_x = points[i].x;
- last_y = points[i].y;
-
-#if 0
- if (points[i].x > clip.x + clip.width)
- break;
-#endif
- }
-
- cairo_line_to (cr, last_x, mid);
- cairo_close_path (cr);
- cairo_stroke_preserve (cr);
- rgba.alpha *= 0.5;
- gdk_cairo_set_source_rgba (cr, &rgba);
- cairo_fill (cr);
- }
-
- cairo_restore (cr);
- }
-
- layout = gtk_widget_create_pango_layout (widget, "");
-
- font_desc = pango_font_description_new ();
- pango_font_description_set_family_static (font_desc, "Monospace");
- pango_font_description_set_absolute_size (font_desc, LABEL_HEIGHT_PX * PANGO_SCALE);
- pango_layout_set_font_description (layout, font_desc);
-
- gdk_cairo_set_source_rgba (cr, &fg);
-
- cairo_move_to (cr, 2, 2);
- if (self->rx_label != NULL)
- pango_layout_set_text (layout, self->rx_label, -1);
- else
- pango_layout_set_text (layout, "RX", 2);
- pango_cairo_show_layout (cr, layout);
-
- cairo_move_to (cr, 2, mid + 2);
- if (self->tx_label != NULL)
- pango_layout_set_text (layout, self->tx_label, -1);
- else
- pango_layout_set_text (layout, "TX", 2);
- pango_cairo_show_layout (cr, layout);
-
- pango_font_description_free (font_desc);
- g_object_unref (layout);
-
- cairo_destroy (cr);
-}
-
-static void
-sysprof_duplex_visualizer_finalize (GObject *object)
-{
- SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)object;
-
- g_clear_pointer (&self->cache, point_cache_unref);
- g_clear_pointer (&self->rx_label, g_free);
- g_clear_pointer (&self->tx_label, g_free);
-
- G_OBJECT_CLASS (sysprof_duplex_visualizer_parent_class)->finalize (object);
-}
-
-static void
-sysprof_duplex_visualizer_class_init (SysprofDuplexVisualizerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
-
- object_class->finalize = sysprof_duplex_visualizer_finalize;
-
- widget_class->snapshot = sysprof_duplex_visualizer_snapshot;
-
- visualizer_class->set_reader = sysprof_duplex_visualizer_set_reader;
-}
-
-static void
-sysprof_duplex_visualizer_init (SysprofDuplexVisualizer *self)
-{
- self->use_diff = TRUE;
-}
-
-GtkWidget *
-sysprof_duplex_visualizer_new (void)
-{
- return g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER, NULL);
-}
-
-void
-sysprof_duplex_visualizer_set_counters (SysprofDuplexVisualizer *self,
- guint rx_counter,
- guint tx_counter)
-{
- g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
- g_return_if_fail (rx_counter != 0);
- g_return_if_fail (tx_counter != 0);
-
- self->rx_counter = rx_counter;
- self->tx_counter = tx_counter;
-}
-
-void
-sysprof_duplex_visualizer_set_colors (SysprofDuplexVisualizer *self,
- const GdkRGBA *rx_rgba,
- const GdkRGBA *tx_rgba)
-{
- g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
-
- if (rx_rgba)
- self->rx_rgba = *rx_rgba;
- self->rx_rgba_set = !!rx_rgba;
-
- if (tx_rgba)
- self->tx_rgba = *tx_rgba;
- self->tx_rgba_set = !!tx_rgba;
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
-}
-
-gboolean
-sysprof_duplex_visualizer_get_use_diff (SysprofDuplexVisualizer *self)
-{
- g_return_val_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self), FALSE);
-
- return self->use_diff;
-}
-
-void
-sysprof_duplex_visualizer_set_use_diff (SysprofDuplexVisualizer *self,
- gboolean use_diff)
-{
- g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
-
- self->use_diff = !!use_diff;
- gtk_widget_queue_allocate (GTK_WIDGET (self));
-}
-
-void
-sysprof_duplex_visualizer_set_labels (SysprofDuplexVisualizer *self,
- const gchar *rx_label,
- const gchar *tx_label)
-{
- g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
-
- if (g_strcmp0 (rx_label, self->rx_label) != 0)
- {
- g_free (self->rx_label);
- self->rx_label = g_strdup (rx_label);
- }
-
- if (g_strcmp0 (tx_label, self->tx_label) != 0)
- {
- g_free (self->tx_label);
- self->tx_label = g_strdup (tx_label);
- }
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
-}
diff --git a/src/libsysprof-ui/sysprof-duplex-visualizer.h b/src/libsysprof-ui/sysprof-duplex-visualizer.h
deleted file mode 100644
index 0b7dec53..00000000
--- a/src/libsysprof-ui/sysprof-duplex-visualizer.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* sysprof-duplex-visualizer.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-visualizer.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_DUPLEX_VISUALIZER (sysprof_duplex_visualizer_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofDuplexVisualizer, sysprof_duplex_visualizer, SYSPROF, DUPLEX_VISUALIZER, SysprofVisualizer)
-
-GtkWidget *sysprof_duplex_visualizer_new (void);
-gboolean sysprof_duplex_visualizer_get_use_diff (SysprofDuplexVisualizer *self);
-void sysprof_duplex_visualizer_set_use_diff (SysprofDuplexVisualizer *self,
- gboolean use_diff);
-void sysprof_duplex_visualizer_set_labels (SysprofDuplexVisualizer *self,
- const gchar *rx_label,
- const gchar *tx_label);
-void sysprof_duplex_visualizer_set_counters (SysprofDuplexVisualizer *self,
- guint rx_counter,
- guint tx_counter);
-void sysprof_duplex_visualizer_set_colors (SysprofDuplexVisualizer *self,
- const GdkRGBA *rx_rgba,
- const GdkRGBA *tx_rgba);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-environ-editor-row.c b/src/libsysprof-ui/sysprof-environ-editor-row.c
deleted file mode 100644
index a7dd7b0c..00000000
--- a/src/libsysprof-ui/sysprof-environ-editor-row.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* sysprof-environ-editor-row.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-environ-editor-row"
-
-#include "config.h"
-
-#include "sysprof-environ-editor-row.h"
-
-struct _SysprofEnvironEditorRow
-{
- GtkListBoxRow parent_instance;
-
- SysprofEnvironVariable *variable;
-
- GtkEntry *key_entry;
- GtkEntry *value_entry;
- GtkButton *delete_button;
-
- GBinding *key_binding;
- GBinding *value_binding;
-};
-
-enum {
- PROP_0,
- PROP_VARIABLE,
- LAST_PROP
-};
-
-enum {
- DELETE,
- LAST_SIGNAL
-};
-
-G_DEFINE_TYPE (SysprofEnvironEditorRow, sysprof_environ_editor_row, GTK_TYPE_LIST_BOX_ROW)
-
-static GParamSpec *properties [LAST_PROP];
-static guint signals [LAST_SIGNAL];
-
-static gboolean
-null_safe_mapping (GBinding *binding,
- const GValue *from_value,
- GValue *to_value,
- gpointer user_data)
-{
- const gchar *str = g_value_get_string (from_value);
- g_value_set_string (to_value, str ?: "");
- return TRUE;
-}
-
-static void
-sysprof_environ_editor_row_connect (SysprofEnvironEditorRow *self)
-{
- g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
- g_assert (SYSPROF_IS_ENVIRON_VARIABLE (self->variable));
-
- self->key_binding =
- g_object_bind_property_full (self->variable, "key", self->key_entry, "text",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
- null_safe_mapping, NULL, NULL, NULL);
-
- self->value_binding =
- g_object_bind_property_full (self->variable, "value", self->value_entry, "text",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
- null_safe_mapping, NULL, NULL, NULL);
-}
-
-static void
-sysprof_environ_editor_row_disconnect (SysprofEnvironEditorRow *self)
-{
- g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
- g_assert (SYSPROF_IS_ENVIRON_VARIABLE (self->variable));
-
- g_clear_pointer (&self->key_binding, g_binding_unbind);
- g_clear_pointer (&self->value_binding, g_binding_unbind);
-}
-
-static void
-delete_button_clicked (GtkButton *button,
- SysprofEnvironEditorRow *self)
-{
- g_assert (GTK_IS_BUTTON (button));
- g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
-
- g_signal_emit (self, signals [DELETE], 0);
-}
-
-static void
-key_entry_activate (GtkWidget *entry,
- SysprofEnvironEditorRow *self)
-{
- g_assert (GTK_IS_ENTRY (entry));
- g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
-
- gtk_widget_grab_focus (GTK_WIDGET (self->value_entry));
-}
-
-static void
-value_entry_activate (GtkWidget *entry,
- SysprofEnvironEditorRow *self)
-{
- GtkWidget *parent;
-
- g_assert (GTK_IS_ENTRY (entry));
- g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
-
- gtk_widget_grab_focus (GTK_WIDGET (self));
- parent = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_LIST_BOX);
- g_signal_emit_by_name (parent, "move-cursor", GTK_MOVEMENT_DISPLAY_LINES, 1);
-}
-
-static void
-sysprof_environ_editor_row_dispose (GObject *object)
-{
- SysprofEnvironEditorRow *self = (SysprofEnvironEditorRow *)object;
-
- if (self->variable != NULL)
- {
- sysprof_environ_editor_row_disconnect (self);
- g_clear_object (&self->variable);
- }
-
- G_OBJECT_CLASS (sysprof_environ_editor_row_parent_class)->dispose (object);
-}
-
-static void
-sysprof_environ_editor_row_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofEnvironEditorRow *self = SYSPROF_ENVIRON_EDITOR_ROW (object);
-
- switch (prop_id)
- {
- case PROP_VARIABLE:
- g_value_set_object (value, sysprof_environ_editor_row_get_variable (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_environ_editor_row_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofEnvironEditorRow *self = SYSPROF_ENVIRON_EDITOR_ROW (object);
-
- switch (prop_id)
- {
- case PROP_VARIABLE:
- sysprof_environ_editor_row_set_variable (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_environ_editor_row_class_init (SysprofEnvironEditorRowClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = sysprof_environ_editor_row_dispose;
- object_class->get_property = sysprof_environ_editor_row_get_property;
- object_class->set_property = sysprof_environ_editor_row_set_property;
-
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-environ-editor-row.ui");
- gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, delete_button);
- gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, key_entry);
- gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, value_entry);
-
- properties [PROP_VARIABLE] =
- g_param_spec_object ("variable",
- "Variable",
- "Variable",
- SYSPROF_TYPE_ENVIRON_VARIABLE,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, LAST_PROP, properties);
-
- signals [DELETE] =
- g_signal_new ("delete",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
-}
-
-static void
-sysprof_environ_editor_row_init (SysprofEnvironEditorRow *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-
- g_signal_connect (self->delete_button,
- "clicked",
- G_CALLBACK (delete_button_clicked),
- self);
-
- g_signal_connect (self->key_entry,
- "activate",
- G_CALLBACK (key_entry_activate),
- self);
-
- g_signal_connect (self->value_entry,
- "activate",
- G_CALLBACK (value_entry_activate),
- self);
-}
-
-/**
- * sysprof_environ_editor_row_get_variable:
- *
- * Returns: (transfer none) (nullable): An #SysprofEnvironVariable.
- */
-SysprofEnvironVariable *
-sysprof_environ_editor_row_get_variable (SysprofEnvironEditorRow *self)
-{
- g_return_val_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self), NULL);
-
- return self->variable;
-}
-
-void
-sysprof_environ_editor_row_set_variable (SysprofEnvironEditorRow *self,
- SysprofEnvironVariable *variable)
-{
- g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
- g_return_if_fail (!variable || SYSPROF_IS_ENVIRON_VARIABLE (variable));
-
- if (variable != self->variable)
- {
- if (self->variable != NULL)
- {
- sysprof_environ_editor_row_disconnect (self);
- g_clear_object (&self->variable);
- }
-
- if (variable != NULL)
- {
- self->variable = g_object_ref (variable);
- sysprof_environ_editor_row_connect (self);
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VARIABLE]);
- }
-}
-
-void
-sysprof_environ_editor_row_start_editing (SysprofEnvironEditorRow *self)
-{
- g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
-
- gtk_widget_grab_focus (GTK_WIDGET (self->key_entry));
-}
diff --git a/src/libsysprof-ui/sysprof-environ-editor-row.h b/src/libsysprof-ui/sysprof-environ-editor-row.h
deleted file mode 100644
index 39437e5a..00000000
--- a/src/libsysprof-ui/sysprof-environ-editor-row.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* ide-environ-editor-row.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-#include "sysprof-environ-variable.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_ENVIRON_EDITOR_ROW (sysprof_environ_editor_row_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofEnvironEditorRow, sysprof_environ_editor_row, SYSPROF, ENVIRON_EDITOR_ROW, GtkListBoxRow)
-
-SysprofEnvironVariable *sysprof_environ_editor_row_get_variable (SysprofEnvironEditorRow *self);
-void sysprof_environ_editor_row_set_variable (SysprofEnvironEditorRow *self,
- SysprofEnvironVariable *variable);
-void sysprof_environ_editor_row_start_editing (SysprofEnvironEditorRow *self);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-environ-editor-row.ui b/src/libsysprof-ui/sysprof-environ-editor-row.ui
deleted file mode 100644
index 8735f770..00000000
--- a/src/libsysprof-ui/sysprof-environ-editor-row.ui
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
- 12
-
-
- 3
- False
-
-
-
-
- =
-
-
-
-
-
- True
- False
-
-
-
-
- Remove environment variable
- list-remove-symbolic
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-environ-editor.c b/src/libsysprof-ui/sysprof-environ-editor.c
deleted file mode 100644
index 7c641aca..00000000
--- a/src/libsysprof-ui/sysprof-environ-editor.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/* sysprof-environ-editor.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-environ-editor"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-environ-editor.h"
-#include "sysprof-environ-editor-row.h"
-#include "sysprof-theme-manager.h"
-
-struct _SysprofEnvironEditor
-{
- GtkWidget parent_instance;
- GtkListBox *list_box;
- SysprofEnviron *environ;
- GtkWidget *dummy_row;
- SysprofEnvironVariable *dummy;
-};
-
-G_DEFINE_TYPE (SysprofEnvironEditor, sysprof_environ_editor, GTK_TYPE_WIDGET)
-
-enum {
- PROP_0,
- PROP_ENVIRON,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-static void
-sysprof_environ_editor_delete_row (SysprofEnvironEditor *self,
- SysprofEnvironEditorRow *row)
-{
- SysprofEnvironVariable *variable;
-
- g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
- g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (row));
-
- variable = sysprof_environ_editor_row_get_variable (row);
- sysprof_environ_remove (self->environ, variable);
-}
-
-static GtkWidget *
-sysprof_environ_editor_create_dummy_row (SysprofEnvironEditor *self)
-{
- GtkWidget *row;
- GtkWidget *label;
-
- g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
-
- label = g_object_new (GTK_TYPE_LABEL,
- "label", _("New environment variable…"),
- "margin-start", 6,
- "margin-end", 6,
- "margin-top", 6,
- "margin-bottom", 6,
- "visible", TRUE,
- "xalign", 0.0f,
- NULL);
- gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
-
- row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
- "child", label,
- "visible", TRUE,
- NULL);
-
- return row;
-}
-
-static GtkWidget *
-sysprof_environ_editor_create_row (gpointer item,
- gpointer user_data)
-{
- SysprofEnvironVariable *variable = item;
- SysprofEnvironEditor *self = user_data;
- SysprofEnvironEditorRow *row;
-
- g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
- g_assert (SYSPROF_IS_ENVIRON_VARIABLE (variable));
-
- row = g_object_new (SYSPROF_TYPE_ENVIRON_EDITOR_ROW,
- "variable", variable,
- "visible", TRUE,
- NULL);
-
- g_signal_connect_object (row,
- "delete",
- G_CALLBACK (sysprof_environ_editor_delete_row),
- self,
- G_CONNECT_SWAPPED);
-
- return GTK_WIDGET (row);
-}
-
-static void
-sysprof_environ_editor_disconnect (SysprofEnvironEditor *self)
-{
- g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
- g_assert (SYSPROF_IS_ENVIRON (self->environ));
-
- gtk_list_box_bind_model (self->list_box, NULL, NULL, NULL, NULL);
- g_clear_object (&self->dummy);
-}
-
-static void
-sysprof_environ_editor_connect (SysprofEnvironEditor *self)
-{
- g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
- g_assert (SYSPROF_IS_ENVIRON (self->environ));
-
- gtk_list_box_bind_model (self->list_box,
- G_LIST_MODEL (self->environ),
- sysprof_environ_editor_create_row, self, NULL);
-
- self->dummy_row = sysprof_environ_editor_create_dummy_row (self);
- gtk_list_box_append (self->list_box, self->dummy_row);
-}
-
-static void
-find_row_cb (GtkWidget *widget,
- gpointer data)
-{
- struct {
- SysprofEnvironVariable *variable;
- SysprofEnvironEditorRow *row;
- } *lookup = data;
-
- g_assert (lookup != NULL);
- g_assert (GTK_IS_LIST_BOX_ROW (widget));
-
- if (SYSPROF_IS_ENVIRON_EDITOR_ROW (widget))
- {
- SysprofEnvironVariable *variable;
-
- variable = sysprof_environ_editor_row_get_variable (SYSPROF_ENVIRON_EDITOR_ROW (widget));
-
- if (variable == lookup->variable)
- lookup->row = SYSPROF_ENVIRON_EDITOR_ROW (widget);
- }
-}
-
-static SysprofEnvironEditorRow *
-find_row (SysprofEnvironEditor *self,
- SysprofEnvironVariable *variable)
-{
- struct {
- SysprofEnvironVariable *variable;
- SysprofEnvironEditorRow *row;
- } lookup = { variable, NULL };
-
- g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
- g_assert (SYSPROF_IS_ENVIRON_VARIABLE (variable));
-
- for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->list_box));
- child;
- child = gtk_widget_get_next_sibling (child))
- find_row_cb (child, &lookup);
-
- return lookup.row;
-}
-
-static void
-sysprof_environ_editor_row_activated (SysprofEnvironEditor *self,
- GtkListBoxRow *row,
- GtkListBox *list_box)
-{
- g_assert (GTK_IS_LIST_BOX (list_box));
- g_assert (GTK_IS_LIST_BOX_ROW (row));
-
- if (self->environ == NULL)
- return;
-
- if (self->dummy_row == GTK_WIDGET (row))
- {
- g_autoptr(SysprofEnvironVariable) variable = NULL;
-
- variable = sysprof_environ_variable_new (NULL, NULL);
- sysprof_environ_append (self->environ, variable);
- sysprof_environ_editor_row_start_editing (find_row (self, variable));
- }
-}
-
-static void
-sysprof_environ_editor_dispose (GObject *object)
-{
- SysprofEnvironEditor *self = (SysprofEnvironEditor *)object;
-
- if (self->list_box)
- {
- gtk_widget_unparent (GTK_WIDGET (self->list_box));
- self->list_box = NULL;
- }
-
- g_clear_object (&self->environ);
-
- G_OBJECT_CLASS (sysprof_environ_editor_parent_class)->dispose (object);
-}
-
-static void
-sysprof_environ_editor_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofEnvironEditor *self = SYSPROF_ENVIRON_EDITOR (object);
-
- switch (prop_id)
- {
- case PROP_ENVIRON:
- g_value_set_object (value, sysprof_environ_editor_get_environ (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_environ_editor_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofEnvironEditor *self = SYSPROF_ENVIRON_EDITOR (object);
-
- switch (prop_id)
- {
- case PROP_ENVIRON:
- sysprof_environ_editor_set_environ (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_environ_editor_class_init (SysprofEnvironEditorClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofThemeManager *theme_manager = sysprof_theme_manager_get_default ();
-
- object_class->dispose = sysprof_environ_editor_dispose;
- object_class->get_property = sysprof_environ_editor_get_property;
- object_class->set_property = sysprof_environ_editor_set_property;
-
- properties [PROP_ENVIRON] =
- g_param_spec_object ("environ",
- "Environment",
- "Environment",
- SYSPROF_TYPE_ENVIRON,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
-
- sysprof_theme_manager_register_resource (theme_manager, NULL, NULL, "/org/gnome/sysprof/css/SysprofEnvironEditor-shared.css");
-}
-
-static void
-sysprof_environ_editor_init (SysprofEnvironEditor *self)
-{
- self->list_box = GTK_LIST_BOX (gtk_list_box_new ());
- gtk_widget_set_parent (GTK_WIDGET (self->list_box), GTK_WIDGET (self));
-
- gtk_list_box_set_selection_mode (self->list_box, GTK_SELECTION_NONE);
-
- gtk_widget_add_css_class (GTK_WIDGET (self), "environ-editor");
-
- g_signal_connect_object (self->list_box,
- "row-activated",
- G_CALLBACK (sysprof_environ_editor_row_activated),
- self,
- G_CONNECT_SWAPPED);
-}
-
-GtkWidget *
-sysprof_environ_editor_new (void)
-{
- return g_object_new (SYSPROF_TYPE_ENVIRON_EDITOR, NULL);
-}
-
-void
-sysprof_environ_editor_set_environ (SysprofEnvironEditor *self,
- SysprofEnviron *environ_)
-{
- g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR (self));
- g_return_if_fail (SYSPROF_IS_ENVIRON (environ_));
-
- if (self->environ != environ_)
- {
- if (self->environ != NULL)
- {
- sysprof_environ_editor_disconnect (self);
- g_clear_object (&self->environ);
- }
-
- if (environ_ != NULL)
- {
- self->environ = g_object_ref (environ_);
- sysprof_environ_editor_connect (self);
- }
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENVIRON]);
- }
-}
-
-/**
- * sysprof_environ_editor_get_environ:
- *
- * Returns: (nullable) (transfer none): An #SysprofEnviron or %NULL.
- *
- * Since: 3.34
- */
-SysprofEnviron *
-sysprof_environ_editor_get_environ (SysprofEnvironEditor *self)
-{
- g_return_val_if_fail (SYSPROF_IS_ENVIRON_EDITOR (self), NULL);
-
- return self->environ;
-}
diff --git a/src/libsysprof-ui/sysprof-environ-variable.c b/src/libsysprof-ui/sysprof-environ-variable.c
deleted file mode 100644
index 660b3457..00000000
--- a/src/libsysprof-ui/sysprof-environ-variable.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* sysprof-environ-variable.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-environ-variable"
-
-#include "config.h"
-
-#include "sysprof-environ-variable.h"
-
-struct _SysprofEnvironVariable
-{
- GObject parent_instance;
- gchar *key;
- gchar *value;
-};
-
-G_DEFINE_TYPE (SysprofEnvironVariable, sysprof_environ_variable, G_TYPE_OBJECT)
-
-enum {
- PROP_0,
- PROP_KEY,
- PROP_VALUE,
- LAST_PROP
-};
-
-static GParamSpec *properties [LAST_PROP];
-
-static void
-sysprof_environ_variable_finalize (GObject *object)
-{
- SysprofEnvironVariable *self = (SysprofEnvironVariable *)object;
-
- g_clear_pointer (&self->key, g_free);
- g_clear_pointer (&self->value, g_free);
-
- G_OBJECT_CLASS (sysprof_environ_variable_parent_class)->finalize (object);
-}
-
-static void
-sysprof_environ_variable_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofEnvironVariable *self = SYSPROF_ENVIRON_VARIABLE(object);
-
- switch (prop_id)
- {
- case PROP_KEY:
- g_value_set_string (value, self->key);
- break;
-
- case PROP_VALUE:
- g_value_set_string (value, self->value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_environ_variable_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofEnvironVariable *self = SYSPROF_ENVIRON_VARIABLE(object);
-
- switch (prop_id)
- {
- case PROP_KEY:
- sysprof_environ_variable_set_key (self, g_value_get_string (value));
- break;
-
- case PROP_VALUE:
- sysprof_environ_variable_set_value (self, g_value_get_string (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_environ_variable_class_init (SysprofEnvironVariableClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_environ_variable_finalize;
- object_class->get_property = sysprof_environ_variable_get_property;
- object_class->set_property = sysprof_environ_variable_set_property;
-
- properties [PROP_KEY] =
- g_param_spec_string ("key",
- "Key",
- "The key for the environment variable",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_VALUE] =
- g_param_spec_string ("value",
- "Value",
- "The value for the environment variable",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, LAST_PROP, properties);
-}
-
-static void
-sysprof_environ_variable_init (SysprofEnvironVariable *self)
-{
-}
-
-const gchar *
-sysprof_environ_variable_get_key (SysprofEnvironVariable *self)
-{
- g_return_val_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self), NULL);
-
- return self->key;
-}
-
-void
-sysprof_environ_variable_set_key (SysprofEnvironVariable *self,
- const gchar *key)
-{
- g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self));
-
- if (g_strcmp0 (key, self->key) != 0)
- {
- g_free (self->key);
- self->key = g_strdup (key);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_KEY]);
- }
-}
-
-const gchar *
-sysprof_environ_variable_get_value (SysprofEnvironVariable *self)
-{
- g_return_val_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self), NULL);
-
- return self->value;
-}
-
-void
-sysprof_environ_variable_set_value (SysprofEnvironVariable *self,
- const gchar *value)
-{
- g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self));
-
- if (g_strcmp0 (value, self->value) != 0)
- {
- g_free (self->value);
- self->value = g_strdup (value);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VALUE]);
- }
-}
-
-SysprofEnvironVariable *
-sysprof_environ_variable_new (const gchar *key,
- const gchar *value)
-{
- return g_object_new (SYSPROF_TYPE_ENVIRON_VARIABLE,
- "key", key,
- "value", value,
- NULL);
-}
diff --git a/src/libsysprof-ui/sysprof-environ-variable.h b/src/libsysprof-ui/sysprof-environ-variable.h
deleted file mode 100644
index ee19876a..00000000
--- a/src/libsysprof-ui/sysprof-environ-variable.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* sysprof-environ-variable.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_ENVIRON_VARIABLE (sysprof_environ_variable_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofEnvironVariable, sysprof_environ_variable, SYSPROF, ENVIRON_VARIABLE, GObject)
-
-SysprofEnvironVariable *sysprof_environ_variable_new (const gchar *key,
- const gchar *value);
-const gchar *sysprof_environ_variable_get_key (SysprofEnvironVariable *self);
-void sysprof_environ_variable_set_key (SysprofEnvironVariable *self,
- const gchar *key);
-const gchar *sysprof_environ_variable_get_value (SysprofEnvironVariable *self);
-void sysprof_environ_variable_set_value (SysprofEnvironVariable *self,
- const gchar *value);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-environ.c b/src/libsysprof-ui/sysprof-environ.c
deleted file mode 100644
index a1200d46..00000000
--- a/src/libsysprof-ui/sysprof-environ.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/* sysprof-environ.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-environ"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-environ.h"
-#include "sysprof-environ-variable.h"
-
-struct _SysprofEnviron
-{
- GObject parent_instance;
- GPtrArray *variables;
-};
-
-static void list_model_iface_init (GListModelInterface *iface);
-
-G_DEFINE_TYPE_EXTENDED (SysprofEnviron, sysprof_environ, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
-
-enum {
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL];
-
-static void
-sysprof_environ_finalize (GObject *object)
-{
- SysprofEnviron *self = (SysprofEnviron *)object;
-
- g_clear_pointer (&self->variables, g_ptr_array_unref);
-
- G_OBJECT_CLASS (sysprof_environ_parent_class)->finalize (object);
-}
-
-static void
-sysprof_environ_class_init (SysprofEnvironClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_environ_finalize;
-
- signals [CHANGED] =
- g_signal_new ("changed",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- g_signal_set_va_marshaller (signals [CHANGED],
- G_TYPE_FROM_CLASS (klass),
- g_cclosure_marshal_VOID__VOIDv);
-}
-
-static void
-sysprof_environ_items_changed (SysprofEnviron *self)
-{
- g_assert (SYSPROF_IS_ENVIRON (self));
-
- g_signal_emit (self, signals [CHANGED], 0);
-}
-
-static void
-sysprof_environ_init (SysprofEnviron *self)
-{
- self->variables = g_ptr_array_new_with_free_func (g_object_unref);
-
- g_signal_connect (self,
- "items-changed",
- G_CALLBACK (sysprof_environ_items_changed),
- NULL);
-}
-
-static GType
-sysprof_environ_get_item_type (GListModel *model)
-{
- return SYSPROF_TYPE_ENVIRON_VARIABLE;
-}
-
-static gpointer
-sysprof_environ_get_item (GListModel *model,
- guint position)
-{
- SysprofEnviron *self = (SysprofEnviron *)model;
-
- g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
- g_return_val_if_fail (position < self->variables->len, NULL);
-
- return g_object_ref (g_ptr_array_index (self->variables, position));
-}
-
-static guint
-sysprof_environ_get_n_items (GListModel *model)
-{
- SysprofEnviron *self = (SysprofEnviron *)model;
-
- g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), 0);
-
- return self->variables->len;
-}
-
-static void
-list_model_iface_init (GListModelInterface *iface)
-{
- iface->get_n_items = sysprof_environ_get_n_items;
- iface->get_item = sysprof_environ_get_item;
- iface->get_item_type = sysprof_environ_get_item_type;
-}
-
-static void
-sysprof_environ_variable_notify (SysprofEnviron *self,
- GParamSpec *pspec,
- SysprofEnvironVariable *variable)
-{
- g_assert (SYSPROF_IS_ENVIRON (self));
-
- g_signal_emit (self, signals [CHANGED], 0);
-}
-
-void
-sysprof_environ_setenv (SysprofEnviron *self,
- const gchar *key,
- const gchar *value)
-{
- guint i;
-
- g_return_if_fail (SYSPROF_IS_ENVIRON (self));
- g_return_if_fail (key != NULL);
-
- for (i = 0; i < self->variables->len; i++)
- {
- SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
- const gchar *var_key = sysprof_environ_variable_get_key (var);
-
- if (g_strcmp0 (key, var_key) == 0)
- {
- if (value == NULL)
- {
- g_ptr_array_remove_index (self->variables, i);
- g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
- return;
- }
-
- sysprof_environ_variable_set_value (var, value);
- return;
- }
- }
-
- if (value != NULL)
- {
- SysprofEnvironVariable *var;
- guint position = self->variables->len;
-
- var = g_object_new (SYSPROF_TYPE_ENVIRON_VARIABLE,
- "key", key,
- "value", value,
- NULL);
- g_signal_connect_object (var,
- "notify",
- G_CALLBACK (sysprof_environ_variable_notify),
- self,
- G_CONNECT_SWAPPED);
- g_ptr_array_add (self->variables, var);
- g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
- }
-}
-
-const gchar *
-sysprof_environ_getenv (SysprofEnviron *self,
- const gchar *key)
-{
- guint i;
-
- g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
- g_return_val_if_fail (key != NULL, NULL);
-
- for (i = 0; i < self->variables->len; i++)
- {
- SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
- const gchar *var_key = sysprof_environ_variable_get_key (var);
-
- if (g_strcmp0 (key, var_key) == 0)
- return sysprof_environ_variable_get_value (var);
- }
-
- return NULL;
-}
-
-/**
- * sysprof_environ_get_environ:
- * @self: An #SysprofEnviron
- *
- * Gets the environment as a set of key=value pairs, suitable for use
- * in various GLib process functions.
- *
- * Returns: (transfer full): A newly allocated string array.
- *
- * Since: 3.32
- */
-gchar **
-sysprof_environ_get_environ (SysprofEnviron *self)
-{
- GPtrArray *ar;
- guint i;
-
- g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
-
- ar = g_ptr_array_new ();
-
- for (i = 0; i < self->variables->len; i++)
- {
- SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
- const gchar *key = sysprof_environ_variable_get_key (var);
- const gchar *value = sysprof_environ_variable_get_value (var);
-
- if (value == NULL)
- value = "";
-
- if (key != NULL)
- g_ptr_array_add (ar, g_strdup_printf ("%s=%s", key, value));
- }
-
- g_ptr_array_add (ar, NULL);
-
- return (gchar **)g_ptr_array_free (ar, FALSE);
-}
-
-SysprofEnviron *
-sysprof_environ_new (void)
-{
- return g_object_new (SYSPROF_TYPE_ENVIRON, NULL);
-}
-
-void
-sysprof_environ_remove (SysprofEnviron *self,
- SysprofEnvironVariable *variable)
-{
- guint i;
-
- g_return_if_fail (SYSPROF_IS_ENVIRON (self));
- g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (variable));
-
- for (i = 0; i < self->variables->len; i++)
- {
- SysprofEnvironVariable *item = g_ptr_array_index (self->variables, i);
-
- if (item == variable)
- {
- g_ptr_array_remove_index (self->variables, i);
- g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
- break;
- }
- }
-}
-
-void
-sysprof_environ_append (SysprofEnviron *self,
- SysprofEnvironVariable *variable)
-{
- guint position;
-
- g_return_if_fail (SYSPROF_IS_ENVIRON (self));
- g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (variable));
-
- position = self->variables->len;
-
- g_signal_connect_object (variable,
- "notify",
- G_CALLBACK (sysprof_environ_variable_notify),
- self,
- G_CONNECT_SWAPPED);
- g_ptr_array_add (self->variables, g_object_ref (variable));
- g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
-}
-
-/**
- * sysprof_environ_copy:
- * @self: An #SysprofEnviron
- *
- * Copies the contents of #SysprofEnviron into a newly allocated #SysprofEnviron.
- *
- * Returns: (transfer full): An #SysprofEnviron.
- *
- * Since: 3.32
- */
-SysprofEnviron *
-sysprof_environ_copy (SysprofEnviron *self)
-{
- g_autoptr(SysprofEnviron) copy = NULL;
-
- g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
-
- copy = sysprof_environ_new ();
- sysprof_environ_copy_into (self, copy, TRUE);
-
- return g_steal_pointer (©);
-}
-
-void
-sysprof_environ_copy_into (SysprofEnviron *self,
- SysprofEnviron *dest,
- gboolean replace)
-{
- g_return_if_fail (SYSPROF_IS_ENVIRON (self));
- g_return_if_fail (SYSPROF_IS_ENVIRON (dest));
-
- for (guint i = 0; i < self->variables->len; i++)
- {
- SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
- const gchar *key = sysprof_environ_variable_get_key (var);
- const gchar *value = sysprof_environ_variable_get_value (var);
-
- if (replace || sysprof_environ_getenv (dest, key) == NULL)
- sysprof_environ_setenv (dest, key, value);
- }
-}
-
-/**
- * ide_environ_parse:
- * @pair: the KEY=VALUE pair
- * @key: (out) (optional): a location for a @key
- * @value: (out) (optional): a location for a @value
- *
- * Parses a KEY=VALUE style key-pair into @key and @value.
- *
- * Returns: %TRUE if @pair was successfully parsed
- *
- * Since: 3.32
- */
-gboolean
-ide_environ_parse (const gchar *pair,
- gchar **key,
- gchar **value)
-{
- const gchar *eq;
-
- g_return_val_if_fail (pair != NULL, FALSE);
-
- if (key != NULL)
- *key = NULL;
-
- if (value != NULL)
- *value = NULL;
-
- if ((eq = strchr (pair, '=')))
- {
- if (key != NULL)
- *key = g_strndup (pair, eq - pair);
-
- if (value != NULL)
- *value = g_strdup (eq + 1);
-
- return TRUE;
- }
-
- return FALSE;
-}
diff --git a/src/libsysprof-ui/sysprof-environ.h b/src/libsysprof-ui/sysprof-environ.h
deleted file mode 100644
index ef5e5f83..00000000
--- a/src/libsysprof-ui/sysprof-environ.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* sysprof-environ.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-#include "sysprof-environ-variable.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_ENVIRON (sysprof_environ_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofEnviron, sysprof_environ, SYSPROF, ENVIRON, GObject)
-
-gboolean ide_environ_parse (const gchar *pair,
- gchar **key,
- gchar **value);
-SysprofEnviron *sysprof_environ_new (void);
-void sysprof_environ_setenv (SysprofEnviron *self,
- const gchar *key,
- const gchar *value);
-const gchar *sysprof_environ_getenv (SysprofEnviron *self,
- const gchar *key);
-gchar **sysprof_environ_get_environ (SysprofEnviron *self);
-void sysprof_environ_append (SysprofEnviron *self,
- SysprofEnvironVariable *variable);
-void sysprof_environ_remove (SysprofEnviron *self,
- SysprofEnvironVariable *variable);
-SysprofEnviron *sysprof_environ_copy (SysprofEnviron *self);
-void sysprof_environ_copy_into (SysprofEnviron *self,
- SysprofEnviron *dest,
- gboolean replace);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-failed-state-view.c b/src/libsysprof-ui/sysprof-failed-state-view.c
deleted file mode 100644
index 6ca02e7d..00000000
--- a/src/libsysprof-ui/sysprof-failed-state-view.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/* sysprof-failed-state-view.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "config.h"
-
-#include "sysprof-failed-state-view.h"
-
-G_DEFINE_TYPE (SysprofFailedStateView, sysprof_failed_state_view, GTK_TYPE_WIDGET)
-
-GtkWidget *
-sysprof_failed_state_view_new (void)
-{
- return g_object_new (SYSPROF_TYPE_FAILED_STATE_VIEW, NULL);
-}
-
-static void
-sysprof_failed_state_view_dispose (GObject *object)
-{
- SysprofFailedStateView *self = (SysprofFailedStateView *)object;
- GtkWidget *child;
-
- while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
- gtk_widget_unparent (child);
-
- G_OBJECT_CLASS (sysprof_failed_state_view_parent_class)->dispose (object);
-}
-
-static void
-sysprof_failed_state_view_class_init (SysprofFailedStateViewClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = sysprof_failed_state_view_dispose;
-
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
- gtk_widget_class_set_template_from_resource (widget_class,
- "/org/gnome/sysprof/ui/sysprof-failed-state-view.ui");
-}
-
-static void
-sysprof_failed_state_view_init (SysprofFailedStateView *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-}
diff --git a/src/libsysprof-ui/sysprof-failed-state-view.ui b/src/libsysprof-ui/sysprof-failed-state-view.ui
deleted file mode 100644
index 8b01a009..00000000
--- a/src/libsysprof-ui/sysprof-failed-state-view.ui
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
- true
- center
-
-
- 36
- 36
- 36
- 36
- vertical
- 12
-
-
- computer-fail-symbolic
- 256
-
-
-
-
-
- Ouch, that hurt!
-
-
-
-
-
-
-
-
-
- Something unexpectedly went wrong while trying to profile your system.
- true
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-line-visualizer.c b/src/libsysprof-ui/sysprof-line-visualizer.c
deleted file mode 100644
index 046be4a8..00000000
--- a/src/libsysprof-ui/sysprof-line-visualizer.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/* sysprof-line-visualizer.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-line-visualizer"
-
-#include "config.h"
-
-#include
-#include
-#include
-
-#include "pointcache.h"
-#include "sysprof-line-visualizer.h"
-
-typedef struct
-{
- /*
- * Our reader as assigned by the visualizer system.
- */
- SysprofCaptureReader *reader;
-
- /*
- * An array of LineInfo which contains information about the counters
- * we need to render.
- */
- GArray *lines;
-
- /*
- * This is our set of cached points to render. Once it is assigned here,
- * it is immutable (and therefore may be shared with worker processes
- * that are rendering the points).
- */
- PointCache *cache;
-
- /* The format for units (such as mHz, Watts, etc). */
- gchar *units;
-
- /*
- * Range of the scale for lower and upper.
- */
- gdouble y_lower;
- gdouble y_upper;
-
- /*
- * If we have a new counter discovered or the reader is set, we might
- * want to delay loading until we return to the main loop. This can
- * help us avoid doing duplicate work.
- */
- guint queued_load;
-
- guint y_lower_set : 1;
- guint y_upper_set : 1;
-} SysprofLineVisualizerPrivate;
-
-typedef struct
-{
- guint id;
- guint type;
- gdouble line_width;
- GdkRGBA foreground;
- GdkRGBA background;
- guint use_default_style : 1;
- guint fill : 1;
- guint use_dash : 1;
-} LineInfo;
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- GArray *lines;
- PointCache *cache;
- gint64 begin_time;
- gint64 end_time;
- gdouble y_lower;
- gdouble y_upper;
- guint y_lower_set : 1;
- guint y_upper_set : 1;
-} LoadData;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF_TYPE_VISUALIZER)
-
-static void sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-static PointCache *sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
- GAsyncResult *result,
- GError **error);
-
-enum {
- PROP_0,
- PROP_Y_LOWER,
- PROP_Y_UPPER,
- PROP_UNITS,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-static const gdouble dashes[] = { 1.0, 2.0 };
-
-static void
-load_data_free (gpointer data)
-{
- LoadData *load = data;
-
- if (load != NULL)
- {
- g_clear_pointer (&load->lines, g_array_unref);
- g_clear_pointer (&load->cursor, sysprof_capture_cursor_unref);
- g_clear_pointer (&load->cache, point_cache_unref);
- g_slice_free (LoadData, load);
- }
-}
-
-static GArray *
-copy_array (GArray *ar)
-{
- GArray *ret;
-
- ret = g_array_sized_new (FALSE, FALSE, g_array_get_element_size (ar), ar->len);
- g_array_set_size (ret, ar->len);
- memcpy (ret->data, ar->data, ar->len * g_array_get_element_size (ret));
-
- return ret;
-}
-
-static void
-sysprof_line_visualizer_snapshot (GtkWidget *widget,
- GtkSnapshot *snapshot)
-{
- static PangoAttrList *attrs = NULL;
- SysprofLineVisualizer *self = (SysprofLineVisualizer *)widget;
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
- g_autofree gchar *upper = NULL;
- GtkStyleContext *style_context;
- PangoLayout *layout;
- cairo_t *cr;
- GtkAllocation alloc;
- GdkRectangle clip;
- GdkRGBA foreground;
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (widget));
- g_assert (snapshot != NULL);
-
- gtk_widget_get_allocation (widget, &alloc);
-
- GTK_WIDGET_CLASS (sysprof_line_visualizer_parent_class)->snapshot (widget, snapshot);
-
- if (priv->cache == NULL)
- return;
-
-#if 0
- if (!gdk_cairo_get_clip_rectangle (cr, &clip))
- return ret;
-#else
- clip.x = 0;
- clip.y = 0;
- clip.width = alloc.width;
- clip.height = alloc.height;
-#endif
-
- cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
-
- style_context = gtk_widget_get_style_context (widget);
- gtk_style_context_get_color (style_context, &foreground);
-
- for (guint line = 0; line < priv->lines->len; line++)
- {
- g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
- const LineInfo *line_info = &g_array_index (priv->lines, LineInfo, line);
- const Point *fpoints;
- guint n_fpoints = 0;
- GdkRGBA color;
-
- fpoints = point_cache_get_points (priv->cache, line_info->id, &n_fpoints);
-
- if (n_fpoints > 0)
- {
- gdouble last_x = 0;
- gdouble last_y = 0;
- guint p;
-
- points = g_new0 (SysprofVisualizerAbsolutePoint, n_fpoints);
-
- sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
- (const SysprofVisualizerRelativePoint *)fpoints,
- n_fpoints,
- points,
- n_fpoints);
-
- for (p = 0; p < n_fpoints; p++)
- {
- if (points[p].x >= clip.x)
- break;
- }
-
- if (p >= n_fpoints)
- goto cleanup;
-
- if (p > 0)
- p--;
-
- last_x = points[p].x;
- last_y = points[p].y;
-
- if (line_info->fill)
- {
- cairo_move_to (cr, last_x, alloc.height);
- cairo_line_to (cr, last_x, last_y);
- }
- else
- {
- cairo_move_to (cr, last_x, last_y);
- }
-
- for (guint i = p + 1; i < n_fpoints; i++)
- {
- cairo_curve_to (cr,
- last_x + ((points[i].x - last_x) / 2),
- last_y,
- last_x + ((points[i].x - last_x) / 2),
- points[i].y,
- points[i].x,
- points[i].y);
-
- last_x = points[i].x;
- last_y = points[i].y;
-
- if (points[i].x > clip.x + clip.width)
- break;
- }
-
- if (line_info->fill)
- {
- cairo_line_to (cr, last_x, alloc.height);
- cairo_close_path (cr);
- }
-
- cairo_set_line_width (cr, line_info->line_width);
-
- if (line_info->use_dash)
- cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
-
- if (line_info->fill)
- {
- gdk_cairo_set_source_rgba (cr, &line_info->background);
- cairo_fill_preserve (cr);
- }
-
- if (line_info->use_default_style)
- color = foreground;
- else
- color = line_info->foreground;
-
- gdk_cairo_set_source_rgba (cr, &color);
- cairo_stroke (cr);
- }
- }
-
- if (!attrs)
- {
- attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_scale_new (0.666));
- }
-
- if (priv->y_upper != 100.0)
- {
- if (priv->units)
- upper = g_strdup_printf ("%lg %s", priv->y_upper, priv->units);
- else
- upper = g_strdup_printf ("%lg", priv->y_upper);
-
- layout = gtk_widget_create_pango_layout (widget, upper);
- pango_layout_set_attributes (layout, attrs);
- cairo_move_to (cr, 2, 2);
- foreground.alpha *= 0.5;
- gdk_cairo_set_source_rgba (cr, &foreground);
- pango_cairo_show_layout (cr, layout);
- g_clear_object (&layout);
- }
-
-cleanup:
- cairo_destroy (cr);
-}
-
-static void
-sysprof_line_visualizer_load_data_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
- g_autoptr(GError) error = NULL;
- g_autoptr(PointCache) cache = NULL;
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
-
- cache = sysprof_line_visualizer_load_data_finish (self, result, &error);
-
- if (cache == NULL)
- {
- g_warning ("%s", error->message);
- return;
- }
-
- g_clear_pointer (&priv->cache, point_cache_unref);
- priv->cache = g_steal_pointer (&cache);
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
-}
-
-static gboolean
-sysprof_line_visualizer_do_reload (gpointer data)
-{
- SysprofLineVisualizer *self = data;
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
-
- priv->queued_load = 0;
-
- if (priv->reader != NULL)
- {
- sysprof_line_visualizer_load_data_async (self,
- NULL,
- sysprof_line_visualizer_load_data_cb,
- NULL);
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-sysprof_line_visualizer_queue_reload (SysprofLineVisualizer *self)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
-
- if (priv->queued_load == 0)
- priv->queued_load = g_idle_add_full (G_PRIORITY_LOW,
- sysprof_line_visualizer_do_reload,
- self,
- NULL);
-}
-
-static void
-sysprof_line_visualizer_set_reader (SysprofVisualizer *row,
- SysprofCaptureReader *reader)
-{
- SysprofLineVisualizer *self = (SysprofLineVisualizer *)row;
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
-
- if (priv->reader != reader)
- {
- if (priv->reader != NULL)
- {
- sysprof_capture_reader_unref (priv->reader);
- priv->reader = NULL;
- }
-
- if (reader != NULL)
- priv->reader = sysprof_capture_reader_ref (reader);
-
- sysprof_line_visualizer_queue_reload (self);
- }
-}
-
-static void
-sysprof_line_visualizer_finalize (GObject *object)
-{
- SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_clear_pointer (&priv->units, g_free);
- g_clear_pointer (&priv->lines, g_array_unref);
- g_clear_pointer (&priv->cache, point_cache_unref);
- g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
-
- g_clear_handle_id (&priv->queued_load, g_source_remove);
-
- G_OBJECT_CLASS (sysprof_line_visualizer_parent_class)->finalize (object);
-}
-
-static void
-sysprof_line_visualizer_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_Y_LOWER:
- g_value_set_double (value, priv->y_lower);
- break;
-
- case PROP_Y_UPPER:
- g_value_set_double (value, priv->y_upper);
- break;
-
- case PROP_UNITS:
- g_value_set_string (value, priv->units);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_line_visualizer_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_Y_LOWER:
- priv->y_lower = g_value_get_double (value);
- priv->y_lower_set = TRUE;
- gtk_widget_queue_allocate (GTK_WIDGET (self));
- break;
-
- case PROP_Y_UPPER:
- priv->y_upper = g_value_get_double (value);
- priv->y_upper_set = TRUE;
- gtk_widget_queue_allocate (GTK_WIDGET (self));
- break;
-
- case PROP_UNITS:
- g_free (priv->units);
- priv->units = g_value_dup_string (value);
- gtk_widget_queue_allocate (GTK_WIDGET (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_line_visualizer_class_init (SysprofLineVisualizerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
-
- object_class->finalize = sysprof_line_visualizer_finalize;
- object_class->get_property = sysprof_line_visualizer_get_property;
- object_class->set_property = sysprof_line_visualizer_set_property;
-
- widget_class->snapshot = sysprof_line_visualizer_snapshot;
-
- visualizer_class->set_reader = sysprof_line_visualizer_set_reader;
-
- properties [PROP_Y_LOWER] =
- g_param_spec_double ("y-lower",
- "Y Lower",
- "The lowest Y value for the visualizer",
- -G_MAXDOUBLE,
- G_MAXDOUBLE,
- 0.0,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_Y_UPPER] =
- g_param_spec_double ("y-upper",
- "Y Upper",
- "The highest Y value for the visualizer",
- -G_MAXDOUBLE,
- G_MAXDOUBLE,
- 100.0,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_UNITS] =
- g_param_spec_string ("units",
- "Units",
- "The format for units (mHz, Watts, etc)",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-sysprof_line_visualizer_init (SysprofLineVisualizer *self)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- priv->lines = g_array_new (FALSE, FALSE, sizeof (LineInfo));
-}
-
-void
-sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
- guint counter_id,
- const GdkRGBA *color)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
- LineInfo line_info = { 0 };
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
- g_assert (priv->lines != NULL);
-
- line_info.id = counter_id;
- line_info.line_width = 1.0;
- line_info.type = SYSPROF_CAPTURE_COUNTER_DOUBLE;
-
- if (color != NULL)
- {
- line_info.foreground = *color;
- line_info.use_default_style = FALSE;
- }
- else
- {
- gdk_rgba_parse (&line_info.foreground, "#000");
- line_info.use_default_style = TRUE;
- }
-
- g_array_append_val (priv->lines, line_info);
-
- if (SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added)
- SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added (self, counter_id);
-
- sysprof_line_visualizer_queue_reload (self);
-}
-
-void
-sysprof_line_visualizer_clear (SysprofLineVisualizer *self)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
-
- if (priv->lines->len > 0)
- g_array_remove_range (priv->lines, 0, priv->lines->len);
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
-}
-
-static inline gboolean
-contains_id (GArray *ar,
- guint id)
-{
- for (guint i = 0; i < ar->len; i++)
- {
- const LineInfo *info = &g_array_index (ar, LineInfo, i);
-
- if (info->id == id)
- return TRUE;
- }
-
- return FALSE;
-}
-
-static inline guint8
-counter_type (LoadData *load,
- guint counter_id)
-{
- for (guint i = 0; i < load->lines->len; i++)
- {
- const LineInfo *info = &g_array_index (load->lines, LineInfo, i);
-
- if (info->id == counter_id)
- return info->type;
- }
-
- return SYSPROF_CAPTURE_COUNTER_DOUBLE;
-}
-
-static inline gdouble
-calc_x (gint64 lower,
- gint64 upper,
- gint64 value)
-{
- return (gdouble)(value - lower) / (gdouble)(upper - lower);
-}
-
-static inline gdouble
-calc_y_double (gdouble lower,
- gdouble upper,
- gdouble value)
-{
- return (value - lower) / (upper - lower);
-}
-
-static inline gdouble
-calc_y_int64 (gint64 lower,
- gint64 upper,
- gint64 value)
-{
- return (gdouble)(value - lower) / (gdouble)(upper - lower);
-}
-
-static bool
-sysprof_line_visualizer_load_data_frame_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- LoadData *load = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
- frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
- g_assert (load != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
- {
- const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
- gdouble x = calc_x (load->begin_time, load->end_time, frame->time);
-
- for (guint i = 0; i < set->n_values; i++)
- {
- const SysprofCaptureCounterValues *group = &set->values[i];
-
- for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
- {
- guint counter_id = group->ids[j];
-
- if (counter_id != 0 && contains_id (load->lines, counter_id))
- {
- gdouble y;
-
- if (counter_type (load, counter_id) == SYSPROF_CAPTURE_COUNTER_DOUBLE)
- y = calc_y_double (load->y_lower, load->y_upper, group->values[j].vdbl);
- else
- y = calc_y_int64 (load->y_lower, load->y_upper, group->values[j].v64);
-
- point_cache_add_point_to_set (load->cache, counter_id, x, y);
- }
- }
- }
- }
-
- return TRUE;
-}
-
-static bool
-sysprof_line_visualizer_load_data_range_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- LoadData *load = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
- frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
- g_assert (load != NULL);
- g_assert (load->y_upper_set == FALSE ||
- load->y_lower_set == FALSE);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
- {
- const SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
-
- for (guint i = 0; i < def->n_counters; i++)
- {
- const SysprofCaptureCounter *ctr = &def->counters[i];
-
- for (guint j = 0; j < load->lines->len; j++)
- {
- LineInfo *info = &g_array_index (load->lines, LineInfo, j);
-
- if (info->id == ctr->id)
- {
- info->type = ctr->type;
- break;
- }
- }
- }
- }
- else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
- {
- const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
-
- for (guint i = 0; i < set->n_values; i++)
- {
- const SysprofCaptureCounterValues *group = &set->values[i];
-
- for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
- {
- guint counter_id = group->ids[j];
-
- if (counter_id != 0 && contains_id (load->lines, counter_id))
- {
- gdouble y;
-
- if (counter_type (load, counter_id) == SYSPROF_CAPTURE_COUNTER_DOUBLE)
- y = group->values[j].vdbl;
- else
- y = group->values[j].v64;
-
- if (!load->y_upper_set)
- load->y_upper = MAX (load->y_upper, y);
-
- if (!load->y_lower_set)
- load->y_lower = MIN (load->y_lower, y);
- }
- }
- }
- }
-
- return TRUE;
-}
-
-static void
-sysprof_line_visualizer_load_data_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- LoadData *load = task_data;
- g_autoptr(GArray) counter_ids = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_LINE_VISUALIZER (source_object));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- counter_ids = g_array_new (FALSE, FALSE, sizeof (guint));
-
- for (guint i = 0; i < load->lines->len; i++)
- {
- const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
- g_array_append_val (counter_ids, line_info->id);
- }
-
- sysprof_capture_cursor_add_condition (load->cursor,
- sysprof_capture_condition_new_where_counter_in (counter_ids->len,
- (guint *)(gpointer)counter_ids->data));
-
- /* If y boundaries are not set, we need to discover them by scaning the data. */
- if (!load->y_lower_set || !load->y_upper_set)
- {
- sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_range_cb, load);
- sysprof_capture_cursor_reset (load->cursor);
-
- /* Add extra boundary for some space above the graph line */
- if (G_MAXDOUBLE - load->y_upper > (load->y_upper * .25))
- load->y_upper = load->y_upper + ((load->y_upper - load->y_lower) * .25);
- }
-
- sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_frame_cb, load);
- g_task_return_pointer (task, g_steal_pointer (&load->cache), (GDestroyNotify)point_cache_unref);
-}
-
-static void
-sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
- g_autoptr(GTask) task = NULL;
- LoadData *load;
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_priority (task, G_PRIORITY_LOW);
- g_task_set_source_tag (task, sysprof_line_visualizer_load_data_async);
-
- if (priv->reader == NULL)
- {
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "No data loaded");
- return;
- }
-
- load = g_slice_new0 (LoadData);
- load->cache = point_cache_new ();
- load->y_lower = priv->y_lower_set ? priv->y_lower : G_MAXDOUBLE;
- load->y_upper = priv->y_upper_set ? priv->y_upper : -G_MAXDOUBLE;
- load->y_lower_set = priv->y_lower_set;
- load->y_upper_set = priv->y_upper_set;
- load->begin_time = sysprof_capture_reader_get_start_time (priv->reader);
- load->end_time = sysprof_capture_reader_get_end_time (priv->reader);
- load->cursor = sysprof_capture_cursor_new (priv->reader);
- load->lines = copy_array (priv->lines);
-
- for (guint i = 0; i < load->lines->len; i++)
- {
- const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
-
- point_cache_add_set (load->cache, line_info->id);
- }
-
- g_task_set_task_data (task, load, load_data_free);
- g_task_run_in_thread (task, sysprof_line_visualizer_load_data_worker);
-}
-
-static PointCache *
-sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
- GAsyncResult *result,
- GError **error)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
- LoadData *state;
-
- g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
- g_assert (G_IS_TASK (result));
-
- state = g_task_get_task_data (G_TASK (result));
-
- if (!priv->y_lower_set && priv->y_lower != state->y_lower)
- {
- priv->y_lower = state->y_lower;
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_Y_LOWER]);
- }
-
- if (!priv->y_upper_set && priv->y_upper != state->y_upper)
- {
- priv->y_upper = state->y_upper;
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_Y_UPPER]);
- }
-
- return g_task_propagate_pointer (G_TASK (result), error);
-}
-
-void
-sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
- guint counter_id,
- gdouble width)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
-
- for (guint i = 0; i < priv->lines->len; i++)
- {
- LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
-
- if (info->id == counter_id)
- {
- info->line_width = width;
- sysprof_line_visualizer_queue_reload (self);
- break;
- }
- }
-}
-
-void
-sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
- guint counter_id,
- const GdkRGBA *color)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
-
- for (guint i = 0; i < priv->lines->len; i++)
- {
- LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
-
- if (info->id == counter_id)
- {
- info->fill = !!color;
- if (color != NULL)
- info->background = *color;
- sysprof_line_visualizer_queue_reload (self);
- break;
- }
- }
-}
-
-void
-sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
- guint counter_id,
- gboolean use_dash)
-{
- SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
-
- for (guint i = 0; i < priv->lines->len; i++)
- {
- LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
-
- if (info->id == counter_id)
- {
- info->use_dash = !!use_dash;
- sysprof_line_visualizer_queue_reload (self);
- break;
- }
- }
-}
diff --git a/src/libsysprof-ui/sysprof-line-visualizer.h b/src/libsysprof-ui/sysprof-line-visualizer.h
deleted file mode 100644
index 4fac8855..00000000
--- a/src/libsysprof-ui/sysprof-line-visualizer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* sysprof-line-visualizer.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-visualizer.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_LINE_VISUALIZER (sysprof_line_visualizer_get_type())
-
-G_DECLARE_DERIVABLE_TYPE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF, LINE_VISUALIZER, SysprofVisualizer)
-
-struct _SysprofLineVisualizerClass
-{
- SysprofVisualizerClass parent_class;
-
- void (*counter_added) (SysprofLineVisualizer *self,
- guint counter_id);
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-GtkWidget *sysprof_line_visualizer_new (void);
-void sysprof_line_visualizer_clear (SysprofLineVisualizer *self);
-void sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
- guint counter_id,
- const GdkRGBA *color);
-void sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
- guint counter_id,
- gdouble width);
-void sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
- guint counter_id,
- const GdkRGBA *color);
-void sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
- guint counter_id,
- gboolean use_dash);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-log-model.c b/src/libsysprof-ui/sysprof-log-model.c
deleted file mode 100644
index 8d67254f..00000000
--- a/src/libsysprof-ui/sysprof-log-model.c
+++ /dev/null
@@ -1,422 +0,0 @@
-/* sysprof-log-model.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-log-model"
-
-#include "config.h"
-
-#include
-#include
-#include
-
-#include "sysprof-log-model.h"
-
-struct _SysprofLogModel
-{
- GObject parent_instance;
- GStringChunk *chunks;
- GArray *items;
- gint64 begin_time;
-};
-
-typedef struct
-{
- gint64 time;
- const gchar *domain;
- const gchar *message;
- guint16 severity;
-} Item;
-
-static gint
-sysprof_log_model_get_n_columns (GtkTreeModel *model)
-{
- return SYSPROF_LOG_MODEL_COLUMN_LAST;
-}
-
-static GType
-sysprof_log_model_get_column_type (GtkTreeModel *model,
- gint column)
-{
- switch (column)
- {
- case SYSPROF_LOG_MODEL_COLUMN_TIME:
- return G_TYPE_INT64;
-
- case SYSPROF_LOG_MODEL_COLUMN_SEVERITY:
- case SYSPROF_LOG_MODEL_COLUMN_DOMAIN:
- case SYSPROF_LOG_MODEL_COLUMN_MESSAGE:
- case SYSPROF_LOG_MODEL_COLUMN_TIME_STRING:
- return G_TYPE_STRING;
-
- default:
- return 0;
- }
-}
-
-static GtkTreePath *
-sysprof_log_model_get_path (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- gint off;
-
- g_assert (SYSPROF_IS_LOG_MODEL (model));
- g_assert (iter != NULL);
-
- off = GPOINTER_TO_INT (iter->user_data);
-
- return gtk_tree_path_new_from_indices (off, -1);
-}
-
-static gboolean
-sysprof_log_model_get_iter (GtkTreeModel *model,
- GtkTreeIter *iter,
- GtkTreePath *path)
-{
- SysprofLogModel *self = (SysprofLogModel *)model;
- gint off;
-
- g_assert (SYSPROF_IS_LOG_MODEL (self));
- g_assert (iter != NULL);
- g_assert (path != NULL);
-
- memset (iter, 0, sizeof *iter);
-
- if (gtk_tree_path_get_depth (path) != 1)
- return FALSE;
-
- off = gtk_tree_path_get_indices (path)[0];
- iter->user_data = GINT_TO_POINTER (off);
-
- return off >= 0 && off < self->items->len;
-}
-
-static gboolean
-sysprof_log_model_iter_next (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- SysprofLogModel *self = (SysprofLogModel *)model;
- gint off;
-
- g_assert (SYSPROF_IS_LOG_MODEL (self));
- g_assert (iter != NULL);
-
- off = GPOINTER_TO_INT (iter->user_data);
- off++;
- iter->user_data = GINT_TO_POINTER (off);
-
- return off < self->items->len;
-}
-
-static gboolean
-sysprof_log_model_iter_nth_child (GtkTreeModel *model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n)
-{
- SysprofLogModel *self = (SysprofLogModel *)model;
-
- g_assert (SYSPROF_IS_LOG_MODEL (self));
- g_assert (iter != NULL);
-
- if (parent != NULL)
- return FALSE;
-
- iter->user_data = GINT_TO_POINTER (n);
-
- return n < self->items->len;
-}
-
-static gint
-sysprof_log_model_iter_n_children (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- SysprofLogModel *self = (SysprofLogModel *)model;
-
- g_assert (SYSPROF_IS_LOG_MODEL (self));
-
- return iter ? 0 : self->items->len;
-}
-
-static gboolean
-sysprof_log_model_iter_has_child (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- return FALSE;
-}
-
-static GtkTreeModelFlags
-sysprof_log_model_get_flags (GtkTreeModel *model)
-{
- return GTK_TREE_MODEL_LIST_ONLY;
-}
-
-static void
-sysprof_log_model_get_value (GtkTreeModel *model,
- GtkTreeIter *iter,
- gint column,
- GValue *value)
-{
- SysprofLogModel *self = (SysprofLogModel *)model;
- const Item *item;
-
- g_assert (SYSPROF_IS_LOG_MODEL (self));
- g_assert (iter != NULL);
- g_assert (column < SYSPROF_LOG_MODEL_COLUMN_LAST);
-
- item = &g_array_index (self->items, Item, GPOINTER_TO_INT (iter->user_data));
-
- switch (column)
- {
- case SYSPROF_LOG_MODEL_COLUMN_TIME_STRING:
- {
- gint64 offset = item->time - self->begin_time;
- gint min = offset / SYSPROF_NSEC_PER_SEC / 60L;
- gint seconds = ((offset - (min * SYSPROF_NSEC_PER_SEC)) / SYSPROF_NSEC_PER_SEC) % 60;
- gint msec = (offset % SYSPROF_NSEC_PER_SEC) / (SYSPROF_NSEC_PER_SEC / 1000L);
-
- g_value_init (value, G_TYPE_STRING);
- g_value_take_string (value,
- g_strdup_printf ("%02d:%02d.%03d", min, seconds, msec));
- }
- break;
-
- case SYSPROF_LOG_MODEL_COLUMN_TIME:
- g_value_init (value, G_TYPE_INT64);
- g_value_set_int64 (value, item->time);
- break;
-
- case SYSPROF_LOG_MODEL_COLUMN_SEVERITY:
- g_value_init (value, G_TYPE_STRING);
- switch (item->severity)
- {
- case G_LOG_LEVEL_MESSAGE:
- g_value_set_static_string (value, _("Message"));
- break;
- case G_LOG_LEVEL_INFO:
- g_value_set_static_string (value, _("Info"));
- break;
- case G_LOG_LEVEL_CRITICAL:
- g_value_set_static_string (value, _("Critical"));
- break;
- case G_LOG_LEVEL_ERROR:
- g_value_set_static_string (value, _("Error"));
- break;
- case G_LOG_LEVEL_DEBUG:
- g_value_set_static_string (value, _("Debug"));
- break;
- case G_LOG_LEVEL_WARNING:
- g_value_set_static_string (value, _("Warning"));
- break;
- default:
- g_value_set_static_string (value, "");
- break;
- }
- break;
-
- case SYSPROF_LOG_MODEL_COLUMN_DOMAIN:
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, item->domain);
- break;
-
- case SYSPROF_LOG_MODEL_COLUMN_MESSAGE:
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, item->message);
- break;
-
- default:
- break;
- }
-}
-
-static void
-tree_model_iface_init (GtkTreeModelIface *iface)
-{
- iface->get_n_columns = sysprof_log_model_get_n_columns;
- iface->get_column_type = sysprof_log_model_get_column_type;
- iface->get_iter = sysprof_log_model_get_iter;
- iface->get_path = sysprof_log_model_get_path;
- iface->iter_next = sysprof_log_model_iter_next;
- iface->iter_n_children = sysprof_log_model_iter_n_children;
- iface->iter_nth_child = sysprof_log_model_iter_nth_child;
- iface->iter_has_child = sysprof_log_model_iter_has_child;
- iface->get_flags = sysprof_log_model_get_flags;
- iface->get_value = sysprof_log_model_get_value;
-}
-
-G_DEFINE_TYPE_WITH_CODE (SysprofLogModel, sysprof_log_model, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, tree_model_iface_init))
-
-static void
-sysprof_log_model_finalize (GObject *object)
-{
- SysprofLogModel *self = (SysprofLogModel *)object;
-
- g_clear_pointer (&self->items, g_array_unref);
- g_clear_pointer (&self->chunks, g_string_chunk_free);
-
- G_OBJECT_CLASS (sysprof_log_model_parent_class)->finalize (object);
-}
-
-static void
-sysprof_log_model_class_init (SysprofLogModelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_log_model_finalize;
-}
-
-static void
-sysprof_log_model_init (SysprofLogModel *self)
-{
- self->chunks = g_string_chunk_new (4096*16);
- self->items = g_array_new (FALSE, FALSE, sizeof (Item));
-}
-
-static bool
-cursor_foreach_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofLogModel *self = user_data;
- SysprofCaptureLog *log = (SysprofCaptureLog *)frame;
- Item item;
-
- g_assert (SYSPROF_IS_LOG_MODEL (self));
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_LOG);
-
- item.time = frame->time;
- item.severity = log->severity;
- item.domain = g_string_chunk_insert_const (self->chunks, log->domain);
- item.message = g_string_chunk_insert_const (self->chunks, log->message);
-
- g_array_append_val (self->items, item);
-
- return TRUE;
-}
-
-static gint
-item_compare (gconstpointer a,
- gconstpointer b)
-{
- const Item *ia = a;
- const Item *ib = b;
-
- if (ia->time < ib->time)
- return -1;
- else if (ia->time > ib->time)
- return 1;
- else
- return 0;
-}
-
-static void
-sysprof_log_model_new_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- g_autoptr(SysprofLogModel) self = NULL;
- SysprofCaptureCursor *cursor = task_data;
- SysprofCaptureReader *reader;
-
- g_assert (G_IS_TASK (task));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- self = g_object_new (SYSPROF_TYPE_LOG_MODEL, NULL);
-
- reader = sysprof_capture_cursor_get_reader (cursor);
- self->begin_time = sysprof_capture_reader_get_start_time (reader);
-
- sysprof_capture_cursor_foreach (cursor, cursor_foreach_cb, self);
- g_array_sort (self->items, item_compare);
-
- g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref);
-}
-
-static void
-sysprof_log_model_selection_foreach_cb (SysprofSelection *selection,
- gint64 begin,
- gint64 end,
- gpointer user_data)
-{
- SysprofCaptureCondition **condition = user_data;
- SysprofCaptureCondition *c;
-
- g_assert (SYSPROF_IS_SELECTION (selection));
- g_assert (condition != NULL);
-
- c = sysprof_capture_condition_new_where_time_between (begin, end);
-
- if (*condition != NULL)
- *condition = sysprof_capture_condition_new_or (g_steal_pointer (&c),
- g_steal_pointer (condition));
- else
- *condition = g_steal_pointer (&c);
-}
-
-void
-sysprof_log_model_new_async (SysprofCaptureReader *reader,
- SysprofSelection *selection,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = {
- SYSPROF_CAPTURE_FRAME_LOG,
- };
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- SysprofCaptureCondition *c;
- g_autoptr(GTask) task = NULL;
-
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- cursor = sysprof_capture_cursor_new (reader);
- c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
-
- if (selection)
- {
- SysprofCaptureCondition *condition = NULL;
-
- sysprof_selection_foreach (selection,
- sysprof_log_model_selection_foreach_cb,
- &condition);
- if (condition)
- c = sysprof_capture_condition_new_and (c, g_steal_pointer (&condition));
- }
-
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
-
- task = g_task_new (NULL, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_log_model_new_async);
- g_task_set_task_data (task,
- g_steal_pointer (&cursor),
- (GDestroyNotify) sysprof_capture_cursor_unref);
- g_task_run_in_thread (task, sysprof_log_model_new_worker);
-}
-
-SysprofLogModel *
-sysprof_log_model_new_finish (GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (G_IS_TASK (result), NULL);
-
- return g_task_propagate_pointer (G_TASK (result), error);
-}
diff --git a/src/libsysprof-ui/sysprof-log-model.h b/src/libsysprof-ui/sysprof-log-model.h
deleted file mode 100644
index 7edb25fa..00000000
--- a/src/libsysprof-ui/sysprof-log-model.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* sysprof-log-model.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-typedef enum
-{
- SYSPROF_LOG_MODEL_COLUMN_TIME,
- SYSPROF_LOG_MODEL_COLUMN_SEVERITY,
- SYSPROF_LOG_MODEL_COLUMN_DOMAIN,
- SYSPROF_LOG_MODEL_COLUMN_MESSAGE,
- SYSPROF_LOG_MODEL_COLUMN_TIME_STRING,
- SYSPROF_LOG_MODEL_COLUMN_LAST
-} SysprofLogModelColumn;
-
-#define SYSPROF_TYPE_LOG_MODEL (sysprof_log_model_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofLogModel, sysprof_log_model, SYSPROF, LOG_MODEL, GObject)
-
-void sysprof_log_model_new_async (SysprofCaptureReader *reader,
- SysprofSelection *selection,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-SysprofLogModel *sysprof_log_model_new_finish (GAsyncResult *result,
- GError **error);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-logs-aid.c b/src/libsysprof-ui/sysprof-logs-aid.c
deleted file mode 100644
index 8807cbe5..00000000
--- a/src/libsysprof-ui/sysprof-logs-aid.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/* sysprof-logs-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-logs-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-logs-aid.h"
-#include "sysprof-logs-page.h"
-#include "sysprof-mark-visualizer.h"
-
-struct _SysprofLogsAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofDisplay *display;
- SysprofCaptureCursor *cursor;
- GArray *log_marks;
-} Present;
-
-G_DEFINE_TYPE (SysprofLogsAid, sysprof_logs_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->log_marks, g_array_unref);
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-static void
-on_group_activated_cb (SysprofVisualizerGroup *group,
- SysprofPage *page)
-{
- SysprofDisplay *display;
-
- g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
- g_assert (SYSPROF_IS_PAGE (page));
-
- display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
- sysprof_display_set_visible_page (display, page);
-}
-
-/**
- * sysprof_logs_aid_new:
- *
- * Create a new #SysprofLogsAid.
- *
- * Returns: (transfer full): a newly created #SysprofLogsAid
- */
-SysprofAid *
-sysprof_logs_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_LOGS_AID, NULL);
-}
-
-static bool
-find_marks_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- Present *p = user_data;
-
- g_assert (frame != NULL);
- g_assert (p != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_LOG)
- {
- SysprofMarkTimeSpan span = { frame->time, frame->time };
- g_array_append_val (p->log_marks, span);
- }
-
- return TRUE;
-}
-
-static gint
-compare_span (const SysprofMarkTimeSpan *a,
- const SysprofMarkTimeSpan *b)
-{
- if (a->kind < b->kind)
- return -1;
-
- if (b->kind < a->kind)
- return 1;
-
- if (a->begin < b->begin)
- return -1;
-
- if (b->begin < a->begin)
- return 1;
-
- if (b->end > a->end)
- return -1;
-
- return 0;
-}
-
-static void
-sysprof_logs_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *p = task_data;
-
- g_assert (G_IS_TASK (task));
- g_assert (p != NULL);
- g_assert (SYSPROF_IS_DISPLAY (p->display));
- g_assert (p->cursor != NULL);
- g_assert (SYSPROF_IS_LOGS_AID (source_object));
-
- sysprof_capture_cursor_foreach (p->cursor, find_marks_cb, p);
- g_array_sort (p->log_marks, (GCompareFunc)compare_span);
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_logs_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType logs[] = {
- SYSPROF_CAPTURE_FRAME_LOG,
- };
- SysprofLogsAid *self = (SysprofLogsAid *)aid;
- g_autoptr(GTask) task = NULL;
- Present p = {0};
-
- g_assert (SYSPROF_IS_LOGS_AID (self));
-
- p.display = g_object_ref (display);
- p.log_marks = g_array_new (FALSE, FALSE, sizeof (SysprofMarkTimeSpan));
- p.cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (p.cursor,
- sysprof_capture_condition_new_where_type_in (1, logs));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_logs_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &p),
- present_free);
- g_task_run_in_thread (task, sysprof_logs_aid_present_worker);
-}
-
-static gboolean
-sysprof_logs_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- Present *p;
-
- g_assert (SYSPROF_IS_LOGS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- p = g_task_get_task_data (G_TASK (result));
-
- if (p->log_marks->len > 0)
- {
- g_autoptr(GHashTable) items = NULL;
- SysprofVisualizerGroup *group;
- SysprofVisualizer *marks;
- SysprofPage *page;
-
- items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) g_array_unref);
- g_hash_table_insert (items, g_strdup (_("Logs")), g_array_ref (p->log_marks));
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "title", _("Logs"),
- "visible", TRUE,
- NULL);
-
- marks = sysprof_mark_visualizer_new (items);
- sysprof_visualizer_set_title (marks, _("Logs"));
- gtk_widget_show (GTK_WIDGET (marks));
- sysprof_visualizer_group_insert (group, marks, 0, FALSE);
- sysprof_display_add_group (p->display, group);
-
- page = g_object_new (SYSPROF_TYPE_LOGS_PAGE,
- "title", _("Logs"),
- "visible", TRUE,
- NULL);
- sysprof_display_add_page (p->display, page);
-
- g_signal_connect_object (group,
- "group-activated",
- G_CALLBACK (on_group_activated_cb),
- page,
- 0);
- }
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_logs_aid_class_init (SysprofLogsAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->present_async = sysprof_logs_aid_present_async;
- aid_class->present_finish = sysprof_logs_aid_present_finish;
-}
-
-static void
-sysprof_logs_aid_init (SysprofLogsAid *self)
-{
-}
diff --git a/src/libsysprof-ui/sysprof-logs-page.c b/src/libsysprof-ui/sysprof-logs-page.c
deleted file mode 100644
index f2b46af8..00000000
--- a/src/libsysprof-ui/sysprof-logs-page.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* sysprof-logs-page.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-logs-page"
-
-#include "config.h"
-
-#include "sysprof-log-model.h"
-#include "sysprof-logs-page.h"
-
-struct _SysprofLogsPage
-{
- SysprofPage parent_instance;
-
- /* Template Widgets */
- GtkTreeView *tree_view;
-};
-
-G_DEFINE_TYPE (SysprofLogsPage, sysprof_logs_page, SYSPROF_TYPE_PAGE)
-
-static void
-sysprof_logs_page_load_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofLogsPage *self;
- g_autoptr(SysprofLogModel) model = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
-
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- if (!(model = sysprof_log_model_new_finish (result, &error)))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- g_task_return_boolean (task, TRUE);
-
- self = g_task_get_source_object (task);
-
- gtk_tree_view_set_model (self->tree_view, GTK_TREE_MODEL (model));
-}
-
-static void
-sysprof_logs_page_load_async (SysprofPage *page,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *filter,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SysprofLogsPage *self = (SysprofLogsPage *)page;
- g_autoptr(GTask) task = NULL;
-
- g_assert (SYSPROF_IS_LOGS_PAGE (self));
- g_assert (reader != NULL);
- g_assert (!selection || SYSPROF_IS_SELECTION (selection));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_logs_page_load_async);
-
- sysprof_log_model_new_async (reader,
- selection,
- cancellable,
- sysprof_logs_page_load_cb,
- g_steal_pointer (&task));
-}
-
-static gboolean
-sysprof_logs_page_load_finish (SysprofPage *page,
- GAsyncResult *result,
- GError **error)
-{
- g_assert (SYSPROF_IS_LOGS_PAGE (page));
- g_assert (G_IS_TASK (result));
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_logs_page_class_init (SysprofLogsPageClass *klass)
-{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
-
- page_class->load_async = sysprof_logs_page_load_async;
- page_class->load_finish = sysprof_logs_page_load_finish;
-
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-logs-page.ui");
- gtk_widget_class_bind_template_child (widget_class, SysprofLogsPage, tree_view);
-}
-
-static void
-sysprof_logs_page_init (SysprofLogsPage *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-}
diff --git a/src/libsysprof-ui/sysprof-logs-page.ui b/src/libsysprof-ui/sysprof-logs-page.ui
deleted file mode 100644
index 2f4d565b..00000000
--- a/src/libsysprof-ui/sysprof-logs-page.ui
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
-
-
- 3
- true
-
-
- false
- Time
-
-
- 0.0
-
-
- 4
-
-
-
-
-
-
- false
- Severity
-
-
- 0.0
-
-
- 1
-
-
-
-
-
-
- false
- true
- Domain
-
-
- 0.0
-
-
- 2
-
-
-
-
-
-
- true
- Message
-
-
- end
- 0.0
-
-
- 3
-
-
-
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-mark-detail.c b/src/libsysprof-ui/sysprof-mark-detail.c
deleted file mode 100644
index d0899149..00000000
--- a/src/libsysprof-ui/sysprof-mark-detail.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* sysprof-mark-detail.c
- *
- * Copyright 2022 Corentin Noël
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-mark-detail"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-mark-detail.h"
-
-struct _SysprofMarkDetail
-{
- GObject parent_instance;
-
- gchar *label;
- gint64 min;
- gint64 max;
- gint64 average;
- gint64 hits;
-};
-
-G_DEFINE_TYPE (SysprofMarkDetail, sysprof_mark_detail, G_TYPE_OBJECT)
-
-enum {
- PROP_0,
- PROP_LABEL,
- PROP_MIN,
- PROP_MAX,
- PROP_AVERAGE,
- PROP_HITS,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-/**
- * sysprof_mark_detail_new:
- *
- * Create a new #SysprofMarkDetail.
- *
- * Returns: (transfer full): a newly created #SysprofMarkDetail
- */
-SysprofMarkDetail *
-sysprof_mark_detail_new (const gchar *mark,
- gint64 min,
- gint64 max,
- gint64 avg,
- gint64 hits)
-{
- return g_object_new (SYSPROF_TYPE_MARK_DETAIL,
- "label", mark,
- "min", min,
- "max", max,
- "average", avg,
- "hits", hits,
- NULL);
-}
-
-static void
-sysprof_mark_detail_finalize (GObject *object)
-{
- SysprofMarkDetail *self = (SysprofMarkDetail *)object;
-
- g_clear_pointer (&self->label, g_free);
-
- G_OBJECT_CLASS (sysprof_mark_detail_parent_class)->finalize (object);
-}
-
-static void
-sysprof_mark_detail_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofMarkDetail *self = SYSPROF_MARK_DETAIL(object);
-
- switch (prop_id)
- {
- case PROP_LABEL:
- g_value_set_string (value, self->label);
- break;
-
- case PROP_MIN:
- g_value_set_int64 (value, self->min);
- break;
-
- case PROP_MAX:
- g_value_set_int64 (value, self->max);
- break;
-
- case PROP_AVERAGE:
- g_value_set_int64 (value, self->average);
- break;
-
- case PROP_HITS:
- g_value_set_int64 (value, self->hits);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_mark_detail_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofMarkDetail *self = SYSPROF_MARK_DETAIL(object);
-
- switch (prop_id)
- {
- case PROP_LABEL:
- g_assert(self->label == NULL);
- self->label = g_value_dup_string (value);
- break;
-
- case PROP_MIN:
- self->min = g_value_get_int64 (value);
- break;
-
- case PROP_MAX:
- self->max = g_value_get_int64 (value);
- break;
-
- case PROP_AVERAGE:
- self->average = g_value_get_int64 (value);
- break;
-
- case PROP_HITS:
- self->hits = g_value_get_int64 (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_mark_detail_class_init (SysprofMarkDetailClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_mark_detail_finalize;
- object_class->get_property = sysprof_mark_detail_get_property;
- object_class->set_property = sysprof_mark_detail_set_property;
-
- properties [PROP_LABEL] =
- g_param_spec_string ("label",
- "Label",
- "The label of the mark",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_MIN] =
- g_param_spec_int64 ("min",
- "Min",
- "The minimal timespan",
- 0, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_MAX] =
- g_param_spec_int64 ("max",
- "max",
- "The maximal timespan",
- 0, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_AVERAGE] =
- g_param_spec_int64 ("average",
- "Average",
- "The average timespan",
- 0, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_HITS] =
- g_param_spec_int64 ("hits",
- "Hits",
- "The number of hits",
- 0, G_MAXINT64, 0,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-sysprof_mark_detail_init (SysprofMarkDetail *self)
-{
-}
diff --git a/src/libsysprof-ui/sysprof-mark-detail.h b/src/libsysprof-ui/sysprof-mark-detail.h
deleted file mode 100644
index 35b292e7..00000000
--- a/src/libsysprof-ui/sysprof-mark-detail.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* sysprof-mark-detail.h
- *
- * Copyright 2022 Corentin Noël
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_MARK_DETAIL (sysprof_mark_detail_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofMarkDetail, sysprof_mark_detail, SYSPROF, MARK_DETAIL, GObject)
-
-SysprofMarkDetail *sysprof_mark_detail_new (const gchar *mark,
- gint64 min,
- gint64 max,
- gint64 avg,
- gint64 hits);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-mark-visualizer.c b/src/libsysprof-ui/sysprof-mark-visualizer.c
deleted file mode 100644
index ab8a67f9..00000000
--- a/src/libsysprof-ui/sysprof-mark-visualizer.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/* sysprof-mark-visualizer.c
- *
- * Copyright 2018-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-mark-visualizer"
-
-#include "config.h"
-
-#include "sysprof-mark-visualizer.h"
-
-#define RECT_HEIGHT (4)
-#define RECT_MIN_WIDTH (3)
-#define RECT_OVERLAP (-1)
-
-struct _SysprofMarkVisualizer
-{
- SysprofVisualizer parent_instance;
- GHashTable *spans_by_group;
- GHashTable *rgba_by_group;
- GHashTable *rgba_by_kind;
- GHashTable *row_by_kind;
- guint x_is_dirty : 1;
-};
-
-G_DEFINE_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF_TYPE_VISUALIZER)
-
-static void
-reset_positions (SysprofMarkVisualizer *self)
-{
- g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
-
- self->x_is_dirty = TRUE;
- gtk_widget_queue_draw (GTK_WIDGET (self));
-}
-
-SysprofVisualizer *
-sysprof_mark_visualizer_new (GHashTable *groups)
-{
- SysprofMarkVisualizer *self;
- guint n_items;
- gint height;
-
- g_return_val_if_fail (groups != NULL, NULL);
-
- self = g_object_new (SYSPROF_TYPE_MARK_VISUALIZER, NULL);
- self->spans_by_group = g_hash_table_ref (groups);
-
- reset_positions (self);
-
- n_items = g_hash_table_size (groups);
- height = MAX (35, n_items * (RECT_HEIGHT - RECT_OVERLAP));
- gtk_widget_set_size_request (GTK_WIDGET (self), -1, height);
-
- return SYSPROF_VISUALIZER (g_steal_pointer (&self));
-}
-
-static void
-sysprof_mark_visualizer_snapshot (GtkWidget *widget,
- GtkSnapshot *snapshot)
-{
- SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
- SysprofVisualizer *vis = (SysprofVisualizer *)widget;
- static const GdkRGBA black = {0,0,0,1};
- const GdkRGBA *rgba = &black;
- GHashTableIter iter;
- GtkAllocation alloc;
- gpointer k, v;
- int n_groups = 0;
- int y = 0;
-
- g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
- g_assert (snapshot != NULL);
-
- GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->snapshot (widget, snapshot);
-
- if (self->spans_by_group == NULL)
- return;
-
- gtk_widget_get_allocation (widget, &alloc);
-
- /* Pre-calculate all time slots so we can join later */
- if (self->x_is_dirty)
- {
- g_hash_table_iter_init (&iter, self->spans_by_group);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- const GArray *spans = v;
-
- for (guint i = 0; i < spans->len; i++)
- {
- SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
-
- span->x = sysprof_visualizer_get_x_for_time (vis, span->begin);
- span->x2 = sysprof_visualizer_get_x_for_time (vis, span->end);
- }
- }
-
- self->x_is_dirty = FALSE;
- }
-
- n_groups = g_hash_table_size (self->spans_by_group);
-
- g_hash_table_iter_init (&iter, self->spans_by_group);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- SysprofMarkTimeSpan *span;
- const gchar *group = k;
- const GArray *spans = v;
- const GdkRGBA *kindrgba;
- const GdkRGBA *grouprgba;
-
- if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
- rgba = grouprgba;
-
- for (guint i = 0; i < spans->len; i++)
- {
- gint x1, x2;
-
- span = &g_array_index (spans, SysprofMarkTimeSpan, i);
-
- if (n_groups == 1)
- {
- rgba = &black;
- if ((kindrgba = g_hash_table_lookup (self->rgba_by_kind, GUINT_TO_POINTER (span->kind))))
- rgba = kindrgba;
- else if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
- rgba = grouprgba;
- }
-
- x1 = span->x;
- x2 = x1 + RECT_MIN_WIDTH;
-
- if (span->x2 > x2)
- x2 = span->x2;
-
- /* If we are limited to one group, we might need to get the row
- * height for the kind of span this is.
- */
- if (n_groups == 1)
- {
- gint row = GPOINTER_TO_INT (g_hash_table_lookup (self->row_by_kind, GUINT_TO_POINTER (span->kind)));
- y = row * (RECT_HEIGHT - RECT_OVERLAP);
- }
-
- for (guint j = i + 1; j < spans->len; j++)
- {
- const SysprofMarkTimeSpan *next = &g_array_index (spans, SysprofMarkTimeSpan, j);
-
- /* Don't join this if we are about to draw a different kind */
- if (n_groups == 1 && next->kind != span->kind)
- break;
-
- if (next->x <= x2)
- {
- x2 = MAX (x2, next->x2);
- i++;
- continue;
- }
-
- break;
- }
-
- gtk_snapshot_append_color (snapshot, rgba, &GRAPHENE_RECT_INIT (x1, y, x2 - x1, RECT_HEIGHT));
- }
-
- y += RECT_HEIGHT + RECT_OVERLAP;
- }
-}
-
-static void
-sysprof_mark_visualizer_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline)
-{
- SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
-
- g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
-
- GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->size_allocate (widget, width, height, baseline);
-
- reset_positions (self);
-}
-
-static void
-sysprof_mark_visualizer_finalize (GObject *object)
-{
- SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)object;
-
- g_clear_pointer (&self->spans_by_group, g_hash_table_unref);
- g_clear_pointer (&self->rgba_by_group, g_hash_table_unref);
- g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
- g_clear_pointer (&self->row_by_kind, g_hash_table_unref);
-
- G_OBJECT_CLASS (sysprof_mark_visualizer_parent_class)->finalize (object);
-}
-
-static void
-sysprof_mark_visualizer_class_init (SysprofMarkVisualizerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->finalize = sysprof_mark_visualizer_finalize;
-
- widget_class->snapshot = sysprof_mark_visualizer_snapshot;
- widget_class->size_allocate = sysprof_mark_visualizer_size_allocate;
-}
-
-static void
-sysprof_mark_visualizer_init (SysprofMarkVisualizer *self)
-{
- self->rgba_by_kind = g_hash_table_new_full (NULL, NULL, NULL, g_free);
- self->row_by_kind = g_hash_table_new (NULL, NULL);
- self->rgba_by_group = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-}
-
-void
-sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
- const gchar *group,
- const GdkRGBA *rgba)
-{
- g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
- g_return_if_fail (group != NULL);
-
- g_hash_table_insert (self->rgba_by_group,
- g_strdup (group),
- g_memdup2 (rgba, sizeof *rgba));
-}
-
-void
-sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
- GHashTable *rgba_by_kind)
-{
- g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
-
- if (rgba_by_kind != self->rgba_by_kind)
- {
- g_hash_table_remove_all (self->row_by_kind);
-
- g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
-
- if (rgba_by_kind)
- {
- GHashTableIter iter;
- guint row = 0;
- gpointer k;
-
- self->rgba_by_kind = g_hash_table_ref (rgba_by_kind);
-
- g_hash_table_iter_init (&iter, rgba_by_kind);
- while (g_hash_table_iter_next (&iter, &k, NULL))
- g_hash_table_insert (self->row_by_kind, k, GUINT_TO_POINTER (row++));
-
- gtk_widget_set_size_request (GTK_WIDGET (self),
- -1,
- MAX (35, row * (RECT_HEIGHT - RECT_OVERLAP)));
- }
- }
-}
diff --git a/src/libsysprof-ui/sysprof-mark-visualizer.h b/src/libsysprof-ui/sysprof-mark-visualizer.h
deleted file mode 100644
index 36327e13..00000000
--- a/src/libsysprof-ui/sysprof-mark-visualizer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* sysprof-mark-visualizer.h
- *
- * Copyright 2018-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-visualizer.h"
-
-G_BEGIN_DECLS
-
-typedef struct
-{
- gint64 begin;
- gint64 end;
- guint kind;
- gint x;
- gint x2;
-} SysprofMarkTimeSpan;
-
-#define SYSPROF_TYPE_MARK_VISUALIZER (sysprof_mark_visualizer_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF, MARK_VISUALIZER, SysprofVisualizer)
-
-SysprofVisualizer *sysprof_mark_visualizer_new (GHashTable *groups);
-void sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
- const gchar *group,
- const GdkRGBA *rgba);
-void sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
- GHashTable *rgba_by_kind);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-marks-aid.c b/src/libsysprof-ui/sysprof-marks-aid.c
deleted file mode 100644
index 4361dfab..00000000
--- a/src/libsysprof-ui/sysprof-marks-aid.c
+++ /dev/null
@@ -1,490 +0,0 @@
-/* sysprof-marks-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-marks-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-marks-aid.h"
-#include "sysprof-marks-page.h"
-#include "sysprof-mark-visualizer.h"
-
-struct _SysprofMarksAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofDisplay *display;
- SysprofCaptureCursor *cursor;
- GHashTable *categories;
- GHashTable *kinds;
- guint last_kind;
- guint has_marks : 1;
-} Present;
-
-G_DEFINE_TYPE (SysprofMarksAid, sysprof_marks_aid, SYSPROF_TYPE_AID)
-
-static void
-rgb_to_hls (gdouble *r,
- gdouble *g,
- gdouble *b)
-{
- gdouble min;
- gdouble max;
- gdouble red;
- gdouble green;
- gdouble blue;
- gdouble h, l, s;
- gdouble delta;
-
- red = *r;
- green = *g;
- blue = *b;
- if (red > green)
- {
- if (red > blue)
- max = red;
- else
- max = blue;
- if (green < blue)
- min = green;
- else
- min = blue;
- }
- else
- {
- if (green > blue)
- max = green;
- else
- max = blue;
- if (red < blue)
- min = red;
- else
- min = blue;
- }
- l = (max + min) / 2;
- s = 0;
- h = 0;
- if (max != min)
- {
- if (l <= 0.5)
- s = (max - min) / (max + min);
- else
- s = (max - min) / (2 - max - min);
- delta = max - min;
- if (red == max)
- h = (green - blue) / delta;
- else if (green == max)
- h = 2 + (blue - red) / delta;
- else if (blue == max)
- h = 4 + (red - green) / delta;
- h *= 60;
- if (h < 0.0)
- h += 360;
- }
- *r = h;
- *g = l;
- *b = s;
-}
-
-static void
-hls_to_rgb (gdouble *h,
- gdouble *l,
- gdouble *s)
-{
- gdouble hue;
- gdouble lightness;
- gdouble saturation;
- gdouble m1, m2;
- gdouble r, g, b;
-
- lightness = *l;
- saturation = *s;
- if (lightness <= 0.5)
- m2 = lightness * (1 + saturation);
- else
- m2 = lightness + saturation - lightness * saturation;
- m1 = 2 * lightness - m2;
- if (saturation == 0)
- {
- *h = lightness;
- *l = lightness;
- *s = lightness;
- }
- else
- {
- hue = *h + 120;
- while (hue > 360)
- hue -= 360;
- while (hue < 0)
- hue += 360;
- if (hue < 60)
- r = m1 + (m2 - m1) * hue / 60;
- else if (hue < 180)
- r = m2;
- else if (hue < 240)
- r = m1 + (m2 - m1) * (240 - hue) / 60;
- else
- r = m1;
- hue = *h;
- while (hue > 360)
- hue -= 360;
- while (hue < 0)
- hue += 360;
- if (hue < 60)
- g = m1 + (m2 - m1) * hue / 60;
- else if (hue < 180)
- g = m2;
- else if (hue < 240)
- g = m1 + (m2 - m1) * (240 - hue) / 60;
- else
- g = m1;
- hue = *h - 120;
- while (hue > 360)
- hue -= 360;
- while (hue < 0)
- hue += 360;
- if (hue < 60)
- b = m1 + (m2 - m1) * hue / 60;
- else if (hue < 180)
- b = m2;
- else if (hue < 240)
- b = m1 + (m2 - m1) * (240 - hue) / 60;
- else
- b = m1;
- *h = r;
- *l = g;
- *s = b;
- }
-}
-
-static void
-rgba_shade (const GdkRGBA *rgba,
- GdkRGBA *dst,
- gdouble k)
-{
- gdouble red;
- gdouble green;
- gdouble blue;
-
- red = rgba->red;
- green = rgba->green;
- blue = rgba->blue;
-
- rgb_to_hls (&red, &green, &blue);
-
- green *= k;
-
- if (green > 1.0)
- green = 1.0;
- else if (green < 0.0)
- green = 0.0;
-
- blue *= k;
-
- if (blue > 1.0)
- blue = 1.0;
- else if (blue < 0.0)
- blue = 0.0;
-
- hls_to_rgb (&red, &green, &blue);
-
- dst->red = red;
- dst->green = green;
- dst->blue = blue;
- dst->alpha = rgba->alpha;
-}
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->categories, g_hash_table_unref);
- g_clear_pointer (&p->kinds, g_hash_table_unref);
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-static void
-on_group_activated_cb (SysprofVisualizerGroup *group,
- SysprofPage *page)
-{
- SysprofDisplay *display;
-
- g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
- g_assert (SYSPROF_IS_PAGE (page));
-
- display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
- sysprof_display_set_visible_page (display, page);
-}
-
-/**
- * sysprof_marks_aid_new:
- *
- * Create a new #SysprofMarksAid.
- *
- * Returns: (transfer full): a newly created #SysprofMarksAid
- */
-SysprofAid *
-sysprof_marks_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_MARKS_AID, NULL);
-}
-
-static bool
-find_marks_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- Present *p = user_data;
-
- g_assert (frame != NULL);
- g_assert (p != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
- {
- const SysprofCaptureMark *mark = (const SysprofCaptureMark *)frame;
- SysprofMarkTimeSpan span = { frame->time, frame->time + mark->duration };
- gchar joined[64];
- gpointer kptr;
- GArray *items;
-
- p->has_marks = TRUE;
-
- if G_UNLIKELY (!(items = g_hash_table_lookup (p->categories, mark->group)))
- {
- items = g_array_new (FALSE, FALSE, sizeof (SysprofMarkTimeSpan));
- g_hash_table_insert (p->categories, g_strdup (mark->group), items);
- }
-
- g_snprintf (joined, sizeof joined, "%s:%s", mark->group, mark->name);
-
- if G_UNLIKELY (!(kptr = g_hash_table_lookup (p->kinds, joined)))
- {
- p->last_kind++;
- kptr = GINT_TO_POINTER (p->last_kind);
- g_hash_table_insert (p->kinds, g_strdup (joined), kptr);
- }
-
- span.kind = GPOINTER_TO_INT (kptr);
-
- g_array_append_val (items, span);
- }
-
- return TRUE;
-}
-
-static gint
-compare_span (const SysprofMarkTimeSpan *a,
- const SysprofMarkTimeSpan *b)
-{
- if (a->kind < b->kind)
- return -1;
-
- if (b->kind < a->kind)
- return 1;
-
- if (a->begin < b->begin)
- return -1;
-
- if (b->begin < a->begin)
- return 1;
-
- if (b->end > a->end)
- return -1;
-
- return 0;
-}
-
-static void
-sysprof_marks_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *p = task_data;
- GHashTableIter iter;
- gpointer k, v;
-
- g_assert (G_IS_TASK (task));
- g_assert (p != NULL);
- g_assert (SYSPROF_IS_DISPLAY (p->display));
- g_assert (p->cursor != NULL);
- g_assert (SYSPROF_IS_MARKS_AID (source_object));
-
- sysprof_capture_cursor_foreach (p->cursor, find_marks_cb, p);
-
- g_hash_table_iter_init (&iter, p->categories);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- GArray *spans = v;
-
- g_array_sort (spans, (GCompareFunc)compare_span);
- }
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_marks_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType marks[] = {
- SYSPROF_CAPTURE_FRAME_MARK,
- };
- SysprofMarksAid *self = (SysprofMarksAid *)aid;
- g_autoptr(GTask) task = NULL;
- Present p = {0};
-
- g_assert (SYSPROF_IS_MARKS_AID (self));
-
- p.display = g_object_ref (display);
- p.categories = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) g_array_unref);
- p.kinds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- p.cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (p.cursor,
- sysprof_capture_condition_new_where_type_in (1, marks));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_marks_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &p),
- present_free);
- g_task_run_in_thread (task, sysprof_marks_aid_present_worker);
-}
-
-static gboolean
-sysprof_marks_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- Present *p;
-
- g_assert (SYSPROF_IS_MARKS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- p = g_task_get_task_data (G_TASK (result));
-
- if (p->has_marks)
- {
- g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
- SysprofVisualizerGroup *group;
- SysprofVisualizer *marks;
- SysprofPage *page;
- GHashTableIter iter;
- gpointer k, v;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "has-page", TRUE,
- "title", _("Timings"),
- "visible", TRUE,
- NULL);
-
- marks = sysprof_mark_visualizer_new (p->categories);
- sysprof_visualizer_set_title (marks, _("Timings"));
- gtk_widget_show (GTK_WIDGET (marks));
-
- g_hash_table_iter_init (&iter, p->categories);
- while (g_hash_table_iter_next (&iter, &k, &v))
- {
- g_autoptr(GHashTable) seen = g_hash_table_new_full (NULL, NULL, NULL, g_free);
- g_autoptr(GHashTable) scoped = NULL;
- SysprofVisualizer *scoped_vis;
- GArray *spans = v;
- const gchar *name = k;
- GdkRGBA rgba;
- GdkRGBA kind_rgba;
- gdouble ratio;
-
- sysprof_color_cycle_next (cycle, &rgba);
- sysprof_mark_visualizer_set_group_rgba (SYSPROF_MARK_VISUALIZER (marks), name, &rgba);
-
- /* Now make a scoped row just for this group */
- scoped = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify)g_array_unref);
- g_hash_table_insert (scoped, g_strdup (name), g_array_ref (spans));
-
- scoped_vis = sysprof_mark_visualizer_new (scoped);
- sysprof_visualizer_set_title (scoped_vis, name);
- sysprof_mark_visualizer_set_group_rgba (SYSPROF_MARK_VISUALIZER (scoped_vis), name, &rgba);
- sysprof_visualizer_group_insert (group, scoped_vis, -1, TRUE);
-
- ratio = .4 / p->last_kind;
-
- for (guint i = 0; i < spans->len; i++)
- {
- const SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
-
- if (!g_hash_table_contains (seen, GUINT_TO_POINTER (span->kind)))
- {
- rgba_shade (&rgba, &kind_rgba, 1 + (ratio * span->kind));
- g_hash_table_insert (seen,
- GUINT_TO_POINTER (span->kind),
- g_memdup2 (&kind_rgba, sizeof kind_rgba));
- }
- }
-
- sysprof_mark_visualizer_set_kind_rgba (SYSPROF_MARK_VISUALIZER (scoped_vis), seen);
- }
-
- page = g_object_new (SYSPROF_TYPE_MARKS_PAGE,
- "zoom-manager", sysprof_display_get_zoom_manager (p->display),
- "visible", TRUE,
- NULL);
-
- g_signal_connect_object (group,
- "group-activated",
- G_CALLBACK (on_group_activated_cb),
- page,
- 0);
-
- sysprof_visualizer_group_insert (group, marks, 0, FALSE);
- sysprof_display_add_group (p->display, group);
- sysprof_display_add_page (p->display, page);
- }
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_marks_aid_class_init (SysprofMarksAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->present_async = sysprof_marks_aid_present_async;
- aid_class->present_finish = sysprof_marks_aid_present_finish;
-}
-
-static void
-sysprof_marks_aid_init (SysprofMarksAid *self)
-{
-}
diff --git a/src/libsysprof-ui/sysprof-marks-model.c b/src/libsysprof-ui/sysprof-marks-model.c
deleted file mode 100644
index 08000641..00000000
--- a/src/libsysprof-ui/sysprof-marks-model.c
+++ /dev/null
@@ -1,592 +0,0 @@
-/* sysprof-marks-model.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-marks-model"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-marks-model.h"
-
-struct _SysprofMarksModel
-{
- GObject parent_instance;
- GStringChunk *chunks;
- GHashTable *counters;
- GArray *items;
- gint64 max_end_time;
-};
-
-typedef struct
-{
- gint64 begin_time;
- gint64 end_time;
- const gchar *group;
- const gchar *name;
- const gchar *message;
- SysprofCaptureCounterValue value;
- guint is_counter : 1;
- guint counter_type : 8;
-} Item;
-
-static void
-counter_free (gpointer data)
-{
- g_slice_free (SysprofCaptureCounter, data);
-}
-
-static gint
-sysprof_marks_model_get_n_columns (GtkTreeModel *model)
-{
- return SYSPROF_MARKS_MODEL_COLUMN_LAST;
-}
-
-static GType
-sysprof_marks_model_get_column_type (GtkTreeModel *model,
- gint column)
-{
- switch (column)
- {
- case SYSPROF_MARKS_MODEL_COLUMN_GROUP:
- return G_TYPE_STRING;
-
- case SYSPROF_MARKS_MODEL_COLUMN_NAME:
- return G_TYPE_STRING;
-
- case SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME:
- return G_TYPE_INT64;
-
- case SYSPROF_MARKS_MODEL_COLUMN_END_TIME:
- return G_TYPE_INT64;
-
- case SYSPROF_MARKS_MODEL_COLUMN_DURATION:
- return G_TYPE_DOUBLE;
-
- case SYSPROF_MARKS_MODEL_COLUMN_TEXT:
- return G_TYPE_STRING;
-
- default:
- return 0;
- }
-}
-
-static GtkTreePath *
-sysprof_marks_model_get_path (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- gint off;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (model));
- g_assert (iter != NULL);
-
- off = GPOINTER_TO_INT (iter->user_data);
-
- return gtk_tree_path_new_from_indices (off, -1);
-}
-
-static gboolean
-sysprof_marks_model_get_iter (GtkTreeModel *model,
- GtkTreeIter *iter,
- GtkTreePath *path)
-{
- SysprofMarksModel *self = (SysprofMarksModel *)model;
- gint off;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (self));
- g_assert (iter != NULL);
- g_assert (path != NULL);
-
- memset (iter, 0, sizeof *iter);
-
- if (gtk_tree_path_get_depth (path) != 1)
- return FALSE;
-
- off = gtk_tree_path_get_indices (path)[0];
- iter->user_data = GINT_TO_POINTER (off);
-
- return off >= 0 && off < self->items->len;
-}
-
-static gboolean
-sysprof_marks_model_iter_next (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- SysprofMarksModel *self = (SysprofMarksModel *)model;
- gint off;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (self));
- g_assert (iter != NULL);
-
- off = GPOINTER_TO_INT (iter->user_data);
- off++;
- iter->user_data = GINT_TO_POINTER (off);
-
- return off < self->items->len;
-}
-
-static gboolean
-sysprof_marks_model_iter_nth_child (GtkTreeModel *model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n)
-{
- SysprofMarksModel *self = (SysprofMarksModel *)model;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (self));
- g_assert (iter != NULL);
-
- if (parent != NULL)
- return FALSE;
-
- iter->user_data = GINT_TO_POINTER (n);
-
- return n < self->items->len;
-}
-
-static gint
-sysprof_marks_model_iter_n_children (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- SysprofMarksModel *self = (SysprofMarksModel *)model;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (self));
-
- return iter ? 0 : self->items->len;
-}
-
-static gboolean
-sysprof_marks_model_iter_has_child (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- return FALSE;
-}
-
-static GtkTreeModelFlags
-sysprof_marks_model_get_flags (GtkTreeModel *model)
-{
- return GTK_TREE_MODEL_LIST_ONLY;
-}
-
-static void
-sysprof_marks_model_get_value (GtkTreeModel *model,
- GtkTreeIter *iter,
- gint column,
- GValue *value)
-{
- SysprofMarksModel *self = (SysprofMarksModel *)model;
- const Item *item;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (self));
- g_assert (iter != NULL);
- g_assert (column < SYSPROF_MARKS_MODEL_COLUMN_LAST);
-
- item = &g_array_index (self->items, Item, GPOINTER_TO_INT (iter->user_data));
-
- switch (column)
- {
- case SYSPROF_MARKS_MODEL_COLUMN_GROUP:
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, item->group);
- break;
-
- case SYSPROF_MARKS_MODEL_COLUMN_NAME:
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, item->name);
- break;
-
- case SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME:
- g_value_init (value, G_TYPE_INT64);
- g_value_set_int64 (value, item->begin_time);
- break;
-
- case SYSPROF_MARKS_MODEL_COLUMN_END_TIME:
- g_value_init (value, G_TYPE_INT64);
- g_value_set_int64 (value, item->end_time);
- break;
-
- case SYSPROF_MARKS_MODEL_COLUMN_DURATION:
- g_value_init (value, G_TYPE_DOUBLE);
- if (item->end_time)
- g_value_set_double (value, (item->end_time - item->begin_time) / (double)(G_USEC_PER_SEC * 1000));
- break;
-
- case SYSPROF_MARKS_MODEL_COLUMN_TEXT:
- g_value_init (value, G_TYPE_STRING);
- if (item->is_counter)
- {
- gchar *val = NULL;
-
- if (item->counter_type == SYSPROF_CAPTURE_COUNTER_DOUBLE)
- val = g_strdup_printf ("%s — %s = %.4lf", item->group, item->name, item->value.vdbl);
- else if (item->counter_type == SYSPROF_CAPTURE_COUNTER_INT64)
- val = g_strdup_printf ("%s — %s = %"G_GINT64_FORMAT, item->group, item->name, item->value.v64);
-
- g_value_take_string (value, g_steal_pointer (&val));
- }
- else
- {
- if (item->message && item->message[0])
- g_value_take_string (value, g_strdup_printf ("%s — %s", item->name, item->message));
- else
- g_value_set_string (value, item->name);
- }
- break;
-
- default:
- break;
- }
-}
-
-static void
-tree_model_iface_init (GtkTreeModelIface *iface)
-{
- iface->get_n_columns = sysprof_marks_model_get_n_columns;
- iface->get_column_type = sysprof_marks_model_get_column_type;
- iface->get_iter = sysprof_marks_model_get_iter;
- iface->get_path = sysprof_marks_model_get_path;
- iface->iter_next = sysprof_marks_model_iter_next;
- iface->iter_n_children = sysprof_marks_model_iter_n_children;
- iface->iter_nth_child = sysprof_marks_model_iter_nth_child;
- iface->iter_has_child = sysprof_marks_model_iter_has_child;
- iface->get_flags = sysprof_marks_model_get_flags;
- iface->get_value = sysprof_marks_model_get_value;
-}
-
-G_DEFINE_TYPE_WITH_CODE (SysprofMarksModel, sysprof_marks_model, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, tree_model_iface_init))
-
-static void
-sysprof_marks_model_finalize (GObject *object)
-{
- SysprofMarksModel *self = (SysprofMarksModel *)object;
-
- g_clear_pointer (&self->counters, g_hash_table_unref);
- g_clear_pointer (&self->items, g_array_unref);
- g_clear_pointer (&self->chunks, g_string_chunk_free);
-
- G_OBJECT_CLASS (sysprof_marks_model_parent_class)->finalize (object);
-}
-
-static void
-sysprof_marks_model_class_init (SysprofMarksModelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_marks_model_finalize;
-}
-
-static void
-sysprof_marks_model_init (SysprofMarksModel *self)
-{
- self->counters = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, counter_free);
- self->chunks = g_string_chunk_new (4096*16);
- self->items = g_array_new (FALSE, FALSE, sizeof (Item));
-}
-
-static bool
-cursor_foreach_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofMarksModel *self = user_data;
- Item item;
-
- g_assert (SYSPROF_IS_MARKS_MODEL (self));
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_MARK ||
- frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
- frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF ||
- frame->type == SYSPROF_CAPTURE_FRAME_FORK);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
- {
- SysprofCaptureMark *mark = (SysprofCaptureMark *)frame;
-
- item.begin_time = frame->time;
- item.end_time = item.begin_time + mark->duration;
- item.group = g_string_chunk_insert_const (self->chunks, mark->group);
- item.name = g_string_chunk_insert_const (self->chunks, mark->name);
- item.message = g_string_chunk_insert_const (self->chunks, mark->message);
- item.value.v64 = 0;
- item.is_counter = FALSE;
- item.counter_type = 0;
-
- if G_LIKELY (item.end_time > self->max_end_time)
- self->max_end_time = item.end_time;
-
- g_array_append_val (self->items, item);
- }
- else if (frame->type == SYSPROF_CAPTURE_FRAME_FORK)
- {
- SysprofCaptureFork *fk = (SysprofCaptureFork *)frame;
- g_autofree gchar *message = g_strdup_printf ("PID: %d, Child PID: %d", frame->pid, fk->child_pid);
-
- item.begin_time = frame->time;
- item.end_time = item.begin_time;
- item.group = g_string_chunk_insert_const (self->chunks, "fork");
- item.name = g_string_chunk_insert_const (self->chunks, "Fork");
- item.message = g_string_chunk_insert_const (self->chunks, message);
- item.value.v64 = 0;
- item.is_counter = FALSE;
- item.counter_type = 0;
-
- g_array_append_val (self->items, item);
- }
- else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
- {
- SysprofCaptureCounterDefine *ctrdef = (SysprofCaptureCounterDefine *)frame;
-
- for (guint i = 0; i < ctrdef->n_counters; i++)
- {
- SysprofCaptureCounter *ctr = &ctrdef->counters[i];
-
- g_hash_table_insert (self->counters,
- GUINT_TO_POINTER ((guint)ctr->id),
- g_slice_dup (SysprofCaptureCounter, ctr));
- }
- }
- else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
- {
- SysprofCaptureCounterSet *ctrset = (SysprofCaptureCounterSet *)frame;
-
- for (guint i = 0; i < ctrset->n_values; i++)
- {
- SysprofCaptureCounterValues *values = &ctrset->values[i];
-
- for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
- {
- guint32 id = values->ids[j];
- SysprofCaptureCounter *ctr = NULL;
-
- if (id == 0)
- break;
-
- if ((ctr = g_hash_table_lookup (self->counters, GUINT_TO_POINTER (id))))
- {
- item.begin_time = frame->time;
- item.end_time = frame->time;
- item.group = ctr->category;
- item.name = ctr->name;
- item.message = NULL;
- item.is_counter = TRUE;
- item.counter_type = ctr->type;
-
- memcpy (&item.value, &values->values[j], sizeof item.value);
-
- g_array_append_val (self->items, item);
- }
- }
-
- }
- }
-
- return TRUE;
-}
-
-static gint
-item_compare (gconstpointer a,
- gconstpointer b)
-{
- const Item *ia = a;
- const Item *ib = b;
-
- if (ia->begin_time < ib->begin_time)
- return -1;
- else if (ia->begin_time > ib->begin_time)
- return 1;
-
- /* Sort items with longer duration first, as they might be
- * "overarching" marks containing other marks.
- */
- if (ia->end_time > ib->end_time)
- return -1;
- else if (ib->end_time > ia->end_time)
- return 1;
-
- return 0;
-}
-
-static void
-sysprof_marks_model_new_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- g_autoptr(SysprofMarksModel) self = NULL;
- SysprofCaptureCursor *cursor = task_data;
-
- g_assert (G_IS_TASK (task));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- self = g_object_new (SYSPROF_TYPE_MARKS_MODEL, NULL);
- sysprof_capture_cursor_foreach (cursor, cursor_foreach_cb, self);
- g_array_sort (self->items, item_compare);
-
- g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref);
-}
-
-static void
-sysprof_marks_model_selection_foreach_cb (SysprofSelection *selection,
- gint64 begin,
- gint64 end,
- gpointer user_data)
-{
- SysprofCaptureCondition **condition = user_data;
- SysprofCaptureCondition *c;
-
- g_assert (SYSPROF_IS_SELECTION (selection));
- g_assert (condition != NULL);
-
- c = sysprof_capture_condition_new_where_time_between (begin, end);
-
- if (*condition != NULL)
- *condition = sysprof_capture_condition_new_or (g_steal_pointer (&c),
- g_steal_pointer (condition));
- else
- *condition = g_steal_pointer (&c);
-}
-
-void
-sysprof_marks_model_new_async (SysprofCaptureReader *reader,
- SysprofMarksModelKind kind,
- SysprofSelection *selection,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType ctrset[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- SysprofCaptureCondition *c;
-
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- cursor = sysprof_capture_cursor_new (reader);
-
- if (kind == SYSPROF_MARKS_MODEL_BOTH)
- {
- static const SysprofCaptureFrameType types[] = {
- SYSPROF_CAPTURE_FRAME_CTRSET,
- SYSPROF_CAPTURE_FRAME_MARK,
- };
-
- c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
- }
- else if (kind == SYSPROF_MARKS_MODEL_MARKS)
- {
- static const SysprofCaptureFrameType types[] = {
- SYSPROF_CAPTURE_FRAME_MARK,
- SYSPROF_CAPTURE_FRAME_FORK,
- };
-
- c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
- }
- else if (kind == SYSPROF_MARKS_MODEL_COUNTERS)
- {
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRSET };
-
- c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
- }
- else
- {
- g_task_report_new_error (NULL, callback, user_data,
- sysprof_marks_model_new_async,
- G_IO_ERROR,
- G_IO_ERROR_INVAL,
- "Invalid arguments");
- return;
- }
-
- if (selection)
- {
- SysprofCaptureCondition *condition = NULL;
-
- sysprof_selection_foreach (selection,
- sysprof_marks_model_selection_foreach_cb,
- &condition);
- if (condition)
- c = sysprof_capture_condition_new_and (c, g_steal_pointer (&condition));
- }
-
- if (kind & SYSPROF_MARKS_MODEL_COUNTERS)
- {
- c = sysprof_capture_condition_new_or (
- sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (ctrset), ctrset),
- g_steal_pointer (&c));
- }
-
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
-
- task = g_task_new (NULL, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_marks_model_new_async);
- g_task_set_task_data (task,
- g_steal_pointer (&cursor),
- (GDestroyNotify) sysprof_capture_cursor_unref);
- g_task_run_in_thread (task, sysprof_marks_model_new_worker);
-}
-
-SysprofMarksModel *
-sysprof_marks_model_new_finish (GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (G_IS_TASK (result), NULL);
-
- return g_task_propagate_pointer (G_TASK (result), error);
-}
-
-void
-sysprof_marks_model_get_range (SysprofMarksModel *self,
- gint64 *begin_time,
- gint64 *end_time)
-{
- g_return_if_fail (SYSPROF_IS_MARKS_MODEL (self));
-
- if (begin_time != NULL)
- {
- *begin_time = 0;
-
- if (self->items->len > 0)
- *begin_time = g_array_index (self->items, Item, 0).begin_time;
- }
-
- if (end_time != NULL)
- *end_time = self->max_end_time;
-}
-
-GType
-sysprof_marks_model_kind_get_type (void)
-{
- static GType type_id;
-
- if (g_once_init_enter (&type_id))
- {
- static const GEnumValue values[] = {
- { SYSPROF_MARKS_MODEL_MARKS, "SYSPROF_MARKS_MODEL_MARKS", "marks" },
- { SYSPROF_MARKS_MODEL_COUNTERS, "SYSPROF_MARKS_MODEL_COUNTERS", "counters" },
- { SYSPROF_MARKS_MODEL_BOTH, "SYSPROF_MARKS_MODEL_BOTH", "both" },
- { 0 },
- };
- GType _type_id = g_enum_register_static ("SysprofMarksModelKind", values);
- g_once_init_leave (&type_id, _type_id);
- }
-
- return type_id;
-}
diff --git a/src/libsysprof-ui/sysprof-marks-model.h b/src/libsysprof-ui/sysprof-marks-model.h
deleted file mode 100644
index 203ad8ec..00000000
--- a/src/libsysprof-ui/sysprof-marks-model.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* sysprof-marks-model.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_MARKS_MODEL (sysprof_marks_model_get_type())
-#define SYSPROF_TYPE_MARKS_MODEL_KIND (sysprof_marks_model_kind_get_type())
-
-typedef enum
-{
- SYSPROF_MARKS_MODEL_COLUMN_GROUP,
- SYSPROF_MARKS_MODEL_COLUMN_NAME,
- SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME,
- SYSPROF_MARKS_MODEL_COLUMN_END_TIME,
- SYSPROF_MARKS_MODEL_COLUMN_DURATION,
- SYSPROF_MARKS_MODEL_COLUMN_TEXT,
-} SysprofMarksModelColumn;
-
-typedef enum
-{
- SYSPROF_MARKS_MODEL_MARKS = 1,
- SYSPROF_MARKS_MODEL_COUNTERS,
- SYSPROF_MARKS_MODEL_BOTH = SYSPROF_MARKS_MODEL_MARKS | SYSPROF_MARKS_MODEL_COUNTERS,
-} SysprofMarksModelKind;
-
-#define SYSPROF_MARKS_MODEL_COLUMN_LAST (SYSPROF_MARKS_MODEL_COLUMN_TEXT+1)
-
-G_DECLARE_FINAL_TYPE (SysprofMarksModel, sysprof_marks_model, SYSPROF, MARKS_MODEL, GObject)
-
-GType sysprof_marks_model_kind_get_type (void) G_GNUC_CONST;
-void sysprof_marks_model_new_async (SysprofCaptureReader *reader,
- SysprofMarksModelKind kind,
- SysprofSelection *selection,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-SysprofMarksModel *sysprof_marks_model_new_finish (GAsyncResult *result,
- GError **error);
-void sysprof_marks_model_get_range (SysprofMarksModel *self,
- gint64 *begin_time,
- gint64 *end_time);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-marks-page.c b/src/libsysprof-ui/sysprof-marks-page.c
deleted file mode 100644
index c08381b9..00000000
--- a/src/libsysprof-ui/sysprof-marks-page.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/* sysprof-marks-page.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-marks-page"
-
-#include "config.h"
-
-#include "sysprof-cell-renderer-duration.h"
-#include "sysprof-marks-model.h"
-#include "sysprof-marks-page.h"
-#include "sysprof-ui-private.h"
-#include "sysprof-zoom-manager.h"
-
-typedef struct
-{
- SysprofMarksModelKind kind;
-
- SysprofZoomManager *zoom_manager;
-
- gint64 capture_begin_time;
- gint64 capture_end_time;
-
- /* Template objects */
- GtkScrolledWindow *scroller;
- GtkTreeView *tree_view;
- GtkBox *details_box;
- GtkTreeViewColumn *duration_column;
- SysprofCellRendererDuration *duration_cell;
- GtkStack *stack;
- GtkLabel *group;
- GtkLabel *mark;
- GtkLabel *time;
- GtkLabel *end;
- GtkLabel *duration;
- GtkTextView *message;
- GtkWidget *failed;
- GtkWidget *marks;
-} SysprofMarksPagePrivate;
-
-enum {
- PROP_0,
- PROP_KIND,
- PROP_ZOOM_MANAGER,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofMarksPage, sysprof_marks_page, SYSPROF_TYPE_PAGE)
-
-static gboolean
-sysprof_marks_page_tree_view_key_press_event_cb (SysprofMarksPage *self,
- guint keyval,
- guint keycode,
- GdkModifierType state,
- GtkEventControllerKey *controller)
-{
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
- gint dir = 0;
-
- g_assert (SYSPROF_MARKS_PAGE (self));
- g_assert (GTK_IS_EVENT_CONTROLLER_KEY (controller));
-
- if ((state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK)) == 0)
- {
- switch (keyval)
- {
- case GDK_KEY_Left:
- dir = -1;
- break;
-
- case GDK_KEY_Right:
- dir = 1;
- break;
-
- default:
- break;
- }
-
- if (dir)
- {
- GtkAdjustment *adj = gtk_scrolled_window_get_hadjustment (priv->scroller);
- gdouble step = gtk_adjustment_get_step_increment (adj);
- gdouble val = CLAMP (gtk_adjustment_get_value (adj) + (step * dir),
- gtk_adjustment_get_lower (adj),
- gtk_adjustment_get_upper (adj));
- gtk_adjustment_set_value (adj, val);
- return GDK_EVENT_STOP;
- }
- }
-
- return GDK_EVENT_PROPAGATE;
-}
-
-static gboolean
-get_first_selected (GtkTreeSelection *selection,
- GtkTreeModel **model,
- GtkTreeIter *iter)
-{
- GtkTreeModel *m;
-
- g_assert (GTK_IS_TREE_SELECTION (selection));
-
- if (gtk_tree_selection_count_selected_rows (selection) != 1)
- return FALSE;
-
- m = gtk_tree_view_get_model (gtk_tree_selection_get_tree_view (selection));
- if (model)
- *model = m;
-
- if (iter)
- {
- GList *paths = gtk_tree_selection_get_selected_rows (selection, model);
- gtk_tree_model_get_iter (m, iter, paths->data);
- g_list_free_full (paths, (GDestroyNotify)gtk_tree_path_free);
- }
-
- return TRUE;
-}
-
-static void
-sysprof_marks_page_selection_changed_cb (SysprofMarksPage *self,
- GtkTreeSelection *selection)
-{
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_MARKS_PAGE (self));
- g_assert (GTK_IS_TREE_SELECTION (selection));
-
- if (get_first_selected (selection, &model, &iter))
- {
- g_autofree gchar *group = NULL;
- g_autofree gchar *name = NULL;
- g_autofree gchar *duration_str = NULL;
- g_autofree gchar *time_str = NULL;
- g_autofree gchar *end_str = NULL;
- g_autofree gchar *text = NULL;
- GtkAdjustment *adj;
- gdouble x;
- gint64 begin_time;
- gint64 end_time;
- gint64 duration;
- gint64 etime;
- gint64 otime;
- gdouble lower;
- gdouble upper;
- gdouble value;
- gdouble page_size;
- gint width;
-
- gtk_tree_model_get (model, &iter,
- SYSPROF_MARKS_MODEL_COLUMN_GROUP, &group,
- SYSPROF_MARKS_MODEL_COLUMN_NAME, &name,
- SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
- SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
- SYSPROF_MARKS_MODEL_COLUMN_TEXT, &text,
- -1);
-
- duration = end_time - begin_time;
- duration_str = _sysprof_format_duration (duration);
-
- otime = begin_time - priv->capture_begin_time;
- time_str = _sysprof_format_duration (otime);
-
- etime = end_time - priv->capture_begin_time;
- end_str = _sysprof_format_duration (etime);
-
- gtk_label_set_label (priv->group, group);
- gtk_label_set_label (priv->mark, name);
- gtk_label_set_label (priv->duration, duration_str);
- gtk_label_set_label (priv->time, time_str);
- gtk_label_set_label (priv->end, end_str);
-
- gtk_text_buffer_set_text (gtk_text_view_get_buffer (priv->message), text, -1);
-
- adj = gtk_scrolled_window_get_hadjustment (priv->scroller);
- width = gtk_tree_view_column_get_width (priv->duration_column);
- x = sysprof_zoom_manager_get_offset_at_time (priv->zoom_manager,
- begin_time - priv->capture_begin_time,
- width);
-
- g_object_get (adj,
- "lower", &lower,
- "upper", &upper,
- "value", &value,
- "page-size", &page_size,
- NULL);
-
- if (x < value)
- gtk_adjustment_set_value (adj, MAX (lower, x - (page_size / 3.0)));
- else if (x > (value + page_size))
- gtk_adjustment_set_value (adj, MIN (upper - page_size, (x - (page_size / 3.0))));
- }
-}
-
-static gboolean
-sysprof_marks_page_tree_view_query_tooltip_cb (SysprofMarksPage *self,
- gint x,
- gint y,
- gboolean keyboard_mode,
- GtkTooltip *tooltip,
- GtkTreeView *tree_view)
-{
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
- GtkTreeViewColumn *column;
- GtkTreePath *path = NULL;
- gint cell_x, cell_y;
- gboolean ret = FALSE;
-
- g_assert (SYSPROF_IS_MARKS_PAGE (self));
- g_assert (GTK_IS_TOOLTIP (tooltip));
- g_assert (GTK_IS_TREE_VIEW (tree_view));
-
- if (gtk_tree_view_get_path_at_pos (tree_view, x, y, &path, &column, &cell_x, &cell_y))
- {
- GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
- GtkTreeIter iter;
-
- if (gtk_tree_model_get_iter (model, &iter, path))
- {
- g_autofree gchar *text = NULL;
- g_autofree gchar *timestr = NULL;
- g_autofree gchar *tooltip_text = NULL;
- g_autofree gchar *durationstr = NULL;
- gint64 begin_time;
- gint64 end_time;
- gint64 duration;
-
- gtk_tree_model_get (model, &iter,
- SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
- SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
- SYSPROF_MARKS_MODEL_COLUMN_TEXT, &text,
- -1);
-
- duration = end_time - begin_time;
- begin_time -= priv->capture_begin_time;
- durationstr = _sysprof_format_duration (duration);
-
- if (duration != 0)
- timestr = g_strdup_printf ("%0.4lf (%s)", begin_time / (gdouble)SYSPROF_NSEC_PER_SEC, durationstr);
- else
- timestr = g_strdup_printf ("%0.4lf", begin_time / (gdouble)SYSPROF_NSEC_PER_SEC);
-
- tooltip_text = g_strdup_printf ("%s: %s", timestr, text);
-
- gtk_tooltip_set_text (tooltip, tooltip_text);
-
- ret = TRUE;
- }
- }
-
- gtk_tree_path_free (path);
-
- return ret;
-}
-
-static void
-sysprof_marks_page_load_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- g_autoptr(SysprofMarksModel) model = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
- SysprofMarksPagePrivate *priv;
- SysprofCaptureReader *reader;
- SysprofMarksPage *self;
-
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- self = g_task_get_source_object (task);
- priv = sysprof_marks_page_get_instance_private (self);
-
- if (!(model = sysprof_marks_model_new_finish (result, &error)))
- {
- g_task_return_error (task, g_steal_pointer (&error));
- return;
- }
-
- reader = g_task_get_task_data (task);
- g_assert (reader != NULL);
-
- priv->capture_begin_time = sysprof_capture_reader_get_start_time (reader);
- priv->capture_end_time = sysprof_capture_reader_get_end_time (reader);
-
- g_object_set (priv->duration_cell,
- "capture-begin-time", priv->capture_begin_time,
- "capture-end-time", priv->capture_end_time,
- "zoom-manager", priv->zoom_manager,
- NULL);
-
- gtk_tree_view_set_model (priv->tree_view, GTK_TREE_MODEL (model));
-
- if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL) == 0)
- gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->failed));
- else
- gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->marks));
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_marks_page_load_async (SysprofPage *page,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *filter,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SysprofMarksPage *self = (SysprofMarksPage *)page;
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
- g_autoptr(GTask) task = NULL;
-
- g_return_if_fail (SYSPROF_IS_MARKS_PAGE (self));
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_marks_page_load_async);
- g_task_set_task_data (task,
- sysprof_capture_reader_ref (reader),
- (GDestroyNotify) sysprof_capture_reader_unref);
-
- sysprof_marks_model_new_async (reader,
- priv->kind,
- selection,
- cancellable,
- sysprof_marks_page_load_cb,
- g_steal_pointer (&task));
-}
-
-static gboolean
-sysprof_marks_page_load_finish (SysprofPage *page,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_MARKS_PAGE (page), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_marks_page_set_hadjustment (SysprofPage *page,
- GtkAdjustment *hadjustment)
-{
- SysprofMarksPage *self = (SysprofMarksPage *)page;
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MARKS_PAGE (self));
- g_assert (!hadjustment || GTK_IS_ADJUSTMENT (hadjustment));
-
- gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);
-}
-
-static void
-sysprof_marks_page_set_size_group (SysprofPage *page,
- GtkSizeGroup *size_group)
-{
- SysprofMarksPage *self = (SysprofMarksPage *)page;
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MARKS_PAGE (self));
- g_assert (GTK_IS_SIZE_GROUP (size_group));
-
- gtk_size_group_add_widget (size_group, GTK_WIDGET (priv->details_box));
-}
-
-static void
-sysprof_marks_page_tree_view_row_activated_cb (SysprofMarksPage *self,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- GtkTreeView *tree_view)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_MARKS_PAGE (self));
- g_assert (path != NULL);
- g_assert (GTK_IS_TREE_VIEW_COLUMN (column));
- g_assert (GTK_IS_TREE_VIEW (tree_view));
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (gtk_tree_model_get_iter (model, &iter, path))
- {
- SysprofDisplay *display;
- gint64 begin_time;
- gint64 end_time;
-
- gtk_tree_model_get (model, &iter,
- SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
- SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
- -1);
-
- display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (self), SYSPROF_TYPE_DISPLAY));
- sysprof_display_add_to_selection (display, begin_time, end_time);
- }
-}
-
-static void
-sysprof_marks_page_finalize (GObject *object)
-{
- SysprofMarksPage *self = (SysprofMarksPage *)object;
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
-
- g_clear_object (&priv->zoom_manager);
-
- G_OBJECT_CLASS (sysprof_marks_page_parent_class)->finalize (object);
-}
-
-static void
-sysprof_marks_page_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofMarksPage *self = SYSPROF_MARKS_PAGE (object);
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_KIND:
- g_value_set_enum (value, priv->kind);
- break;
-
- case PROP_ZOOM_MANAGER:
- g_value_set_object (value, priv->zoom_manager);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_marks_page_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofMarksPage *self = SYSPROF_MARKS_PAGE (object);
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_KIND:
- priv->kind = g_value_get_enum (value);
- break;
-
- case PROP_ZOOM_MANAGER:
- if (g_set_object (&priv->zoom_manager, g_value_get_object (value)))
- {
- g_object_set (priv->duration_cell,
- "zoom-manager", priv->zoom_manager,
- NULL);
- if (priv->zoom_manager)
- g_signal_connect_object (priv->zoom_manager,
- "notify::zoom",
- G_CALLBACK (gtk_tree_view_column_queue_resize),
- priv->duration_column,
- G_CONNECT_SWAPPED);
- }
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_marks_page_class_init (SysprofMarksPageClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
-
- object_class->finalize = sysprof_marks_page_finalize;
- object_class->get_property = sysprof_marks_page_get_property;
- object_class->set_property = sysprof_marks_page_set_property;
-
- page_class->load_async = sysprof_marks_page_load_async;
- page_class->load_finish = sysprof_marks_page_load_finish;
- page_class->set_hadjustment = sysprof_marks_page_set_hadjustment;
- page_class->set_size_group = sysprof_marks_page_set_size_group;
-
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-marks-page.ui");
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, end);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, details_box);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration_cell);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration_column);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, scroller);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, stack);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, tree_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, group);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, mark);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, time);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, message);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, marks);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, failed);
-
- properties [PROP_KIND] =
- g_param_spec_enum ("kind", NULL, NULL,
- SYSPROF_TYPE_MARKS_MODEL_KIND,
- SYSPROF_MARKS_MODEL_MARKS,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_ZOOM_MANAGER] =
- g_param_spec_object ("zoom-manager", NULL, NULL,
- SYSPROF_TYPE_ZOOM_MANAGER,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_DURATION);
-}
-
-static void
-sysprof_marks_page_init (SysprofMarksPage *self)
-{
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
- GtkEventController *controller;
-
- priv->kind = SYSPROF_MARKS_MODEL_MARKS;
-
- gtk_widget_init_template (GTK_WIDGET (self));
-
- gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->tree_view),
- GTK_SELECTION_MULTIPLE);
-
- controller = gtk_event_controller_key_new ();
- gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
- g_signal_connect_object (controller,
- "key-pressed",
- G_CALLBACK (sysprof_marks_page_tree_view_key_press_event_cb),
- self,
- G_CONNECT_SWAPPED);
- gtk_widget_add_controller (GTK_WIDGET (self), controller);
-
- g_signal_connect_object (priv->tree_view,
- "row-activated",
- G_CALLBACK (sysprof_marks_page_tree_view_row_activated_cb),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->tree_view,
- "query-tooltip",
- G_CALLBACK (sysprof_marks_page_tree_view_query_tooltip_cb),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (gtk_tree_view_get_selection (priv->tree_view),
- "changed",
- G_CALLBACK (sysprof_marks_page_selection_changed_cb),
- self,
- G_CONNECT_SWAPPED);
-}
-
-GtkWidget *
-sysprof_marks_page_new (SysprofZoomManager *zoom_manager,
- SysprofMarksModelKind kind)
-{
- SysprofMarksPage *self;
- SysprofMarksPagePrivate *priv;
-
- g_return_val_if_fail (SYSPROF_IS_ZOOM_MANAGER (zoom_manager), NULL);
-
- self = g_object_new (SYSPROF_TYPE_MARKS_PAGE,
- "zoom-manager", zoom_manager,
- NULL);
- priv = sysprof_marks_page_get_instance_private (self);
- priv->kind = kind;
-
- return GTK_WIDGET (self);
-}
-
-void
-_sysprof_marks_page_set_hadjustment (SysprofMarksPage *self,
- GtkAdjustment *hadjustment)
-{
- SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_MARKS_PAGE (self));
- g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
-
- gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);
-}
diff --git a/src/libsysprof-ui/sysprof-marks-page.ui b/src/libsysprof-ui/sysprof-marks-page.ui
deleted file mode 100644
index 49936079..00000000
--- a/src/libsysprof-ui/sysprof-marks-page.ui
+++ /dev/null
@@ -1,259 +0,0 @@
-
-
-
-
-
- false
- false
-
-
- horizontal
-
-
- vertical
-
-
- Details
- 0
- 6
- 6
- 6
- 6
-
-
-
-
-
-
-
- false
- true
- 6
- 6
- 6
- 3
-
-
- Group
- 1
-
-
- 0
- 0
-
-
-
-
-
- Mark
- 1
- 0
-
-
- 1
- 0
-
-
-
-
-
- Time
- 1
-
-
- 2
- 0
-
-
-
-
-
- End
- 1
-
-
- 3
- 0
-
-
-
-
-
- Duration
- 1
-
-
- 4
- 0
-
-
-
-
-
- Message
- 1
- 0
-
-
- 5
- 0
-
-
-
-
-
- 0
- true
-
- 0
- 1
-
-
-
-
-
- 0
- 5
- end
-
- 1
- 1
-
-
-
-
-
- 0
-
- 2
- 1
-
-
-
-
-
- 0
-
- 3
- 1
-
-
-
-
-
- 0
-
- 4
- 1
-
-
-
-
-
- true
-
-
- false
-
-
-
- 5
- 1
-
-
-
-
-
-
-
-
-
- vertical
-
-
-
-
- external
- true
-
-
- horizontal
- true
-
-
- Duration
- true
-
-
- 0
- 1
-
-
- 5
- 2
- 3
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
- center
- vertical
- 12
- center
-
-
- computer-fail-symbolic
- 128
-
-
-
-
- No Timings Available
-
-
-
-
-
-
-
-
-
- No timing data was found for the current selection
- true
- true
-
-
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-memory-aid.c b/src/libsysprof-ui/sysprof-memory-aid.c
deleted file mode 100644
index 67341ace..00000000
--- a/src/libsysprof-ui/sysprof-memory-aid.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* sysprof-memory-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-memory-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-memory-aid.h"
-
-struct _SysprofMemoryAid
-{
- SysprofAid parent_instance;
-};
-
-G_DEFINE_TYPE (SysprofMemoryAid, sysprof_memory_aid, SYSPROF_TYPE_AID)
-
-SysprofAid *
-sysprof_memory_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_MEMORY_AID, NULL);
-}
-
-static void
-sysprof_memory_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
-#ifdef __linux__
- g_autoptr(SysprofSource) source = NULL;
-
- g_assert (SYSPROF_IS_MEMORY_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- source = sysprof_memory_source_new ();
- sysprof_profiler_add_source (profiler, source);
-#endif
-}
-
-static void
-sysprof_memory_aid_class_init (SysprofMemoryAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_memory_aid_prepare;
-}
-
-static void
-sysprof_memory_aid_init (SysprofMemoryAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Memory Usage"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-memory-aid.h b/src/libsysprof-ui/sysprof-memory-aid.h
deleted file mode 100644
index d33a1d8c..00000000
--- a/src/libsysprof-ui/sysprof-memory-aid.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* sysprof-memory-aid.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-aid.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_MEMORY_AID (sysprof_memory_aid_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofMemoryAid, sysprof_memory_aid, SYSPROF, MEMORY_AID, SysprofAid)
-
-SysprofAid *sysprof_memory_aid_new (void);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-memprof-aid.c b/src/libsysprof-ui/sysprof-memprof-aid.c
deleted file mode 100644
index 21325177..00000000
--- a/src/libsysprof-ui/sysprof-memprof-aid.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/* sysprof-memprof-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-memprof-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-memprof-aid.h"
-#include "sysprof-memprof-page.h"
-#include "sysprof-memprof-source.h"
-#include "sysprof-memprof-visualizer.h"
-
-struct _SysprofMemprofAid
-{
- SysprofAid parent_instance;
-};
-
-G_DEFINE_TYPE (SysprofMemprofAid, sysprof_memprof_aid, SYSPROF_TYPE_AID)
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
- guint has_allocs : 1;
-} Present;
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-static void
-on_group_activated_cb (SysprofVisualizerGroup *group,
- SysprofPage *page)
-{
- SysprofDisplay *display;
-
- g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
- g_assert (SYSPROF_IS_PAGE (page));
-
- display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
- sysprof_display_set_visible_page (display, page);
-}
-
-SysprofAid *
-sysprof_memprof_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_MEMPROF_AID, NULL);
-}
-
-static void
-sysprof_memprof_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
-#ifdef __linux__
- g_autoptr(SysprofSource) source = NULL;
-
- g_assert (SYSPROF_IS_MEMPROF_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- source = sysprof_memprof_source_new ();
- sysprof_profiler_add_source (profiler, source);
-#endif
-}
-
-static bool
-discover_samples_cb (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- Present *p = user_data;
-
- g_assert (frame != NULL);
- g_assert (p != NULL);
-
- if (frame->type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
- {
- p->has_allocs = TRUE;
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-sysprof_memprof_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *p = task_data;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_MEMPROF_AID (source_object));
- g_assert (p != NULL);
- g_assert (p->cursor != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- sysprof_capture_cursor_foreach (p->cursor, discover_samples_cb, p);
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-sysprof_memprof_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_ALLOCATION };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_MEMPROF_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (1, types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_memprof_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_memprof_aid_present_worker);
-}
-
-static gboolean
-sysprof_memprof_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- Present *p;
-
- g_assert (SYSPROF_IS_MEMPROF_AID (aid));
- g_assert (G_IS_TASK (result));
-
- p = g_task_get_task_data (G_TASK (result));
-
- if (p->has_allocs)
- {
- SysprofVisualizerGroup *group;
- SysprofVisualizer *row;
- SysprofPage *page;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "has-page", TRUE,
- "priority", -300,
- "title", _("Memory"),
- "visible", TRUE,
- NULL);
-
- row = sysprof_memprof_visualizer_new (FALSE);
- sysprof_visualizer_group_insert (group, row, 0, FALSE);
-
- row = sysprof_memprof_visualizer_new (TRUE);
- sysprof_visualizer_group_insert (group, row, 1, FALSE);
-
- page = g_object_new (SYSPROF_TYPE_MEMPROF_PAGE,
- "title", _("Memory Allocations"),
- "vexpand", TRUE,
- "visible", TRUE,
- NULL);
- sysprof_display_add_page (p->display, page);
-
- g_signal_connect_object (group,
- "group-activated",
- G_CALLBACK (on_group_activated_cb),
- page,
- 0);
-
- sysprof_display_add_group (p->display, group);
- }
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_memprof_aid_class_init (SysprofMemprofAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_memprof_aid_prepare;
- aid_class->present_async = sysprof_memprof_aid_present_async;
- aid_class->present_finish = sysprof_memprof_aid_present_finish;
-}
-
-static void
-sysprof_memprof_aid_init (SysprofMemprofAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Track Allocations"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-memprof-page.c b/src/libsysprof-ui/sysprof-memprof-page.c
deleted file mode 100644
index 00e98961..00000000
--- a/src/libsysprof-ui/sysprof-memprof-page.c
+++ /dev/null
@@ -1,1552 +0,0 @@
-/* sysprof-memprof-page.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-/* Sysprof -- Sampling, systemwide CPU profiler
- * Copyright 2004, Red Hat, Inc.
- * Copyright 2004, 2005, 2006, Soeren Sandmann
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include
-
-#include "../stackstash.h"
-
-#include "egg-paned-private.h"
-
-#include "sysprof-cell-renderer-percent.h"
-#include "sysprof-memprof-page.h"
-#include "sysprof-profile.h"
-
-typedef struct
-{
- SysprofMemprofProfile *profile;
-
- GtkTreeView *callers_view;
- GtkTreeView *functions_view;
- GtkTreeView *descendants_view;
- GtkTreeViewColumn *descendants_name_column;
- GtkTreeViewColumn *function_size_column;
- GtkCellRendererText *function_size_cell;
- GtkStack *stack;
- GtkToggleButton *summary;
- GtkToggleButton *all_allocs;
- GtkToggleButton *temp_allocs;
- GtkToggleButton *leaked_allocs_button;
- GtkLabel *temp_allocs_count;
- GtkLabel *num_allocs;
- GtkLabel *leaked_allocs;
- GtkListBox *by_size;
- GtkWidget *callgraph;
- GtkWidget *summary_page;
- GtkWidget *loading_state;
- GtkWidget *empty_state;
-
- GCancellable *cancellable;
-
- GQueue *history;
-
- SysprofMemprofMode mode;
-
- guint profile_size;
- guint loading;
-} SysprofMemprofPagePrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofMemprofPage, sysprof_memprof_page, SYSPROF_TYPE_PAGE)
-
-enum {
- PROP_0,
- PROP_PROFILE,
- N_PROPS
-};
-
-enum {
- GO_PREVIOUS,
- N_SIGNALS
-};
-
-enum {
- COLUMN_NAME,
- COLUMN_SELF,
- COLUMN_TOTAL,
- COLUMN_POINTER,
- COLUMN_SIZE,
-};
-
-static void sysprof_memprof_page_update_descendants (SysprofMemprofPage *self,
- StackNode *node);
-
-static GParamSpec *properties [N_PROPS];
-static guint signals [N_SIGNALS];
-
-static guint
-sysprof_memprof_page_get_profile_size (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- StackStash *stash;
- StackNode *node;
- guint size = 0;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
-
- if (priv->profile_size != 0)
- return priv->profile_size;
-
- if (priv->profile == NULL)
- return 0;
-
- if (NULL == (stash = sysprof_memprof_profile_get_stash (priv->profile)))
- return 0;
-
- for (node = stack_stash_get_root (stash); node != NULL; node = node->siblings)
- size += node->total;
-
- priv->profile_size = size;
-
- return size;
-}
-
-static void
-build_functions_store (StackNode *node,
- gpointer user_data)
-{
- struct {
- GtkListStore *store;
- gdouble profile_size;
- } *state = user_data;
- GtkTreeIter iter;
- const StackNode *n;
- guint64 size = 0;
- guint64 total = 0;
-
- g_assert (state != NULL);
- g_assert (GTK_IS_LIST_STORE (state->store));
-
- for (n = node; n != NULL; n = n->next)
- {
- size += n->size;
- if (n->toplevel)
- total += n->total;
- }
-
- gtk_list_store_append (state->store, &iter);
- gtk_list_store_set (state->store, &iter,
- COLUMN_NAME, U64_TO_POINTER (node->data),
- COLUMN_SELF, 100.0 * size / state->profile_size,
- COLUMN_TOTAL, 100.0 * total / state->profile_size,
- COLUMN_POINTER, node,
- COLUMN_SIZE, (guint64)total,
- -1);
-
-}
-
-static void
-update_summary (SysprofMemprofPage *self,
- SysprofMemprofProfile *profile)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- SysprofMemprofStats stats;
- g_autoptr(GString) str = NULL;
- GtkWidget *child;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (SYSPROF_IS_MEMPROF_PROFILE (profile));
-
- sysprof_memprof_profile_get_stats (profile, &stats);
-
- str = g_string_new (NULL);
-
- g_string_append_printf (str, "%"G_GINT64_FORMAT, stats.n_allocs);
- gtk_label_set_label (priv->num_allocs, str->str);
- g_string_truncate (str, 0);
-
- g_string_append_printf (str, "%"G_GINT64_FORMAT, stats.leaked_allocs);
- gtk_label_set_label (priv->leaked_allocs, str->str);
- g_string_truncate (str, 0);
-
- g_string_append_printf (str, "%"G_GINT64_FORMAT, stats.temp_allocs);
- gtk_label_set_label (priv->temp_allocs_count, str->str);
- g_string_truncate (str, 0);
-
- while ((child = gtk_widget_get_first_child (GTK_WIDGET (priv->by_size))))
- gtk_list_box_remove (priv->by_size, child);
-
- for (guint i = 0; i < G_N_ELEMENTS (stats.by_size); i++)
- {
- g_autofree gchar *prevstr = NULL;
- g_autofree gchar *sizestr = NULL;
- g_autofree gchar *title_str = NULL;
- g_autofree gchar *subtitle_str = NULL;
- g_autofree gchar *allocstr = NULL;
- g_autofree gchar *tempstr = NULL;
- g_autofree gchar *allstr = NULL;
- GtkWidget *row;
- GtkWidget *title;
- GtkWidget *subtitle;
- GtkWidget *prog;
- GtkWidget *box;
-
- if (stats.by_size[i].n_allocs == 0)
- continue;
-
- row = gtk_list_box_row_new ();
- title = gtk_label_new (NULL);
- subtitle = gtk_label_new (NULL);
- prog = gtk_level_bar_new_for_interval (0, stats.n_allocs);
- box = g_object_new (GTK_TYPE_BOX,
- "orientation", GTK_ORIENTATION_VERTICAL,
- "spacing", 6,
- "margin-top", 6,
- "margin-start", 6,
- "margin-bottom", 6,
- "margin-end", 6,
- NULL);
-
- sizestr = g_format_size_full (stats.by_size[i].bucket, G_FORMAT_SIZE_IEC_UNITS);
- if (i == 0)
- {
- title_str = g_strdup_printf ("≤ %s", sizestr);
- }
- else
- {
- /* translators: %s is replaced with a memory size such as "32 bytes" */
- prevstr = g_format_size_full (stats.by_size[i-1].bucket, G_FORMAT_SIZE_IEC_UNITS);
- /* translators: %s is replaced with the the lower and upper bound memory sizes in bytes */
- title_str = g_strdup_printf (_("> %s to %s"), prevstr, sizestr);
- }
-
- gtk_label_set_label (GTK_LABEL (title), title_str);
- gtk_label_set_xalign (GTK_LABEL (title), 0);
- gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (title)), "dim-label");
-
- gtk_widget_set_margin_start (box, 6);
- gtk_widget_set_margin_end (box, 6);
-
- gtk_widget_set_margin_top (prog, 1);
- gtk_widget_set_margin_bottom (prog, 1);
-
- allocstr = g_strdup_printf ("%"G_GINT64_FORMAT, stats.by_size[i].n_allocs);
- tempstr = g_strdup_printf ("%"G_GINT64_FORMAT, stats.by_size[i].temp_allocs);
- allstr = g_format_size_full (stats.by_size[i].allocated,
- G_FORMAT_SIZE_IEC_UNITS);
- subtitle_str = g_strdup_printf ("%s allocations, %s temporary, %s",
- allocstr, tempstr, allstr);
-
- gtk_label_set_label (GTK_LABEL (subtitle), subtitle_str);
- gtk_label_set_xalign (GTK_LABEL (subtitle), 0);
-
-#if 0
- /* TODO: Make this chunked by [temp][rest]... */
- gtk_level_bar_add_offset_value (GTK_LEVEL_BAR (prog),
- GTK_LEVEL_BAR_OFFSET_HIGH,
- stats.by_size[i].temp_allocs);
- gtk_level_bar_add_offset_value (GTK_LEVEL_BAR (prog),
- GTK_LEVEL_BAR_OFFSET_LOW,
- stats.by_size[i].n_allocs);
-#endif
- gtk_level_bar_set_value (GTK_LEVEL_BAR (prog),
- stats.by_size[i].n_allocs);
-
- gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
- gtk_box_append (GTK_BOX (box), title);
- gtk_box_append (GTK_BOX (box), prog);
- gtk_box_append (GTK_BOX (box), subtitle);
- gtk_list_box_append (priv->by_size, row);
- }
-}
-
-static void
-sysprof_memprof_page_load (SysprofMemprofPage *self,
- SysprofMemprofProfile *profile)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkListStore *functions;
- StackStash *stash;
- StackNode *n;
- GtkTreeIter iter;
- struct {
- GtkListStore *store;
- gdouble profile_size;
- } state = { 0 };
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (SYSPROF_IS_MEMPROF_PROFILE (profile));
-
- /*
- * TODO: This is probably the type of thing we want to do off the main
- * thread. We should be able to build the tree models off thread
- * and then simply apply them on the main thread.
- *
- * In the mean time, we should set the state of the widget to
- * insensitive and give some indication of loading progress.
- */
-
- if (!g_set_object (&priv->profile, profile))
- return;
-
- update_summary (self, profile);
-
- if (sysprof_memprof_profile_is_empty (profile))
- {
- gtk_stack_set_visible_child (priv->stack, priv->summary_page);
- return;
- }
-
- stash = sysprof_memprof_profile_get_stash (profile);
-
- for (n = stack_stash_get_root (stash); n; n = n->siblings)
- state.profile_size += n->total;
-
- functions = gtk_list_store_new (5,
- G_TYPE_STRING,
- G_TYPE_DOUBLE,
- G_TYPE_DOUBLE,
- G_TYPE_POINTER,
- G_TYPE_UINT64);
-
- state.store = functions;
- stack_stash_foreach_by_address (stash, build_functions_store, &state);
-
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (functions),
- COLUMN_TOTAL,
- GTK_SORT_DESCENDING);
-
- gtk_tree_view_set_model (priv->functions_view, GTK_TREE_MODEL (functions));
- gtk_tree_view_set_model (priv->callers_view, NULL);
- gtk_tree_view_set_model (priv->descendants_view, NULL);
-
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (functions), &iter))
- {
- GtkTreeSelection *selection;
-
- selection = gtk_tree_view_get_selection (priv->functions_view);
- gtk_tree_selection_select_iter (selection, &iter);
- }
-
- gtk_stack_set_visible_child (priv->stack, priv->callgraph);
-
- g_clear_object (&functions);
-}
-
-void
-_sysprof_memprof_page_set_failed (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_MEMPROF_PAGE (self));
-
- gtk_stack_set_visible_child (priv->stack, priv->empty_state);
-}
-
-static void
-sysprof_memprof_page_unload (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (SYSPROF_IS_MEMPROF_PROFILE (priv->profile));
-
- g_queue_clear (priv->history);
- g_clear_object (&priv->profile);
- priv->profile_size = 0;
-
- gtk_tree_view_set_model (priv->callers_view, NULL);
- gtk_tree_view_set_model (priv->functions_view, NULL);
- gtk_tree_view_set_model (priv->descendants_view, NULL);
-
- gtk_stack_set_visible_child (priv->stack, priv->empty_state);
-}
-
-/**
- * sysprof_memprof_page_get_profile:
- *
- * Returns: (transfer none): An #SysprofMemprofProfile.
- */
-SysprofMemprofProfile *
-sysprof_memprof_page_get_profile (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_MEMPROF_PAGE (self), NULL);
-
- return priv->profile;
-}
-
-void
-sysprof_memprof_page_set_profile (SysprofMemprofPage *self,
- SysprofMemprofProfile *profile)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_MEMPROF_PAGE (self));
- g_return_if_fail (!profile || SYSPROF_IS_MEMPROF_PROFILE (profile));
-
- if (profile != priv->profile)
- {
- if (priv->profile)
- sysprof_memprof_page_unload (self);
-
- if (profile)
- sysprof_memprof_page_load (self, profile);
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROFILE]);
- }
-}
-
-static void
-sysprof_memprof_page_expand_descendants (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeModel *model;
- GList *all_paths = NULL;
- GtkTreePath *first_path;
- GtkTreeIter iter;
- gdouble top_value = 0;
- gint max_rows = 40; /* FIXME */
- gint n_rows;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
-
- model = gtk_tree_view_get_model (priv->descendants_view);
- first_path = gtk_tree_path_new_first ();
- all_paths = g_list_prepend (all_paths, first_path);
- n_rows = 1;
-
- gtk_tree_model_get_iter (model, &iter, first_path);
- gtk_tree_model_get (model, &iter,
- COLUMN_TOTAL, &top_value,
- -1);
-
- while ((all_paths != NULL) && (n_rows < max_rows))
- {
- GtkTreeIter best_iter;
- GtkTreePath *best_path = NULL;
- GList *list;
- gdouble best_value = 0.0;
- gint n_children;
- gint i;
-
- for (list = all_paths; list != NULL; list = list->next)
- {
- GtkTreePath *path = list->data;
-
- g_assert (path != NULL);
-
- if (gtk_tree_model_get_iter (model, &iter, path))
- {
- gdouble value;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_TOTAL, &value,
- -1);
-
- if (value >= best_value)
- {
- best_value = value;
- best_path = path;
- best_iter = iter;
- }
- }
- }
-
- n_children = gtk_tree_model_iter_n_children (model, &best_iter);
-
- if ((n_children > 0) &&
- ((best_value / top_value) > 0.04) &&
- ((n_children + gtk_tree_path_get_depth (best_path)) / (gdouble)max_rows) < (best_value / top_value))
- {
- gtk_tree_view_expand_row (priv->descendants_view, best_path, FALSE);
- n_rows += n_children;
-
- if (gtk_tree_path_get_depth (best_path) < 4)
- {
- GtkTreePath *path;
-
- path = gtk_tree_path_copy (best_path);
- gtk_tree_path_down (path);
-
- for (i = 0; i < n_children; i++)
- {
- all_paths = g_list_prepend (all_paths, path);
-
- path = gtk_tree_path_copy (path);
- gtk_tree_path_next (path);
- }
-
- gtk_tree_path_free (path);
- }
- }
-
- all_paths = g_list_remove (all_paths, best_path);
-
- /* Always expand at least once */
- if ((all_paths == NULL) && (n_rows == 1))
- gtk_tree_view_expand_row (priv->descendants_view, best_path, FALSE);
-
- gtk_tree_path_free (best_path);
- }
-
- g_list_free_full (all_paths, (GDestroyNotify)gtk_tree_path_free);
-}
-
-typedef struct
-{
- StackNode *node;
- const gchar *name;
- guint self;
- guint total;
-} Caller;
-
-static Caller *
-caller_new (StackNode *node)
-{
- Caller *c;
-
- c = g_slice_new (Caller);
- c->name = U64_TO_POINTER (node->data);
- c->self = 0;
- c->total = 0;
- c->node = node;
-
- return c;
-}
-
-static void
-caller_free (gpointer data)
-{
- Caller *c = data;
- g_slice_free (Caller, c);
-}
-
-static void
-sysprof_memprof_page_function_selection_changed (SysprofMemprofPage *self,
- GtkTreeSelection *selection)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeModel *model = NULL;
- GtkTreeIter iter;
- GtkListStore *callers_store;
- g_autoptr(GHashTable) callers = NULL;
- g_autoptr(GHashTable) processed = NULL;
- StackNode *callees = NULL;
- StackNode *node;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (GTK_IS_TREE_SELECTION (selection));
-
- if (!gtk_tree_selection_get_selected (selection, &model, &iter))
- {
- gtk_tree_view_set_model (priv->callers_view, NULL);
- gtk_tree_view_set_model (priv->descendants_view, NULL);
- return;
- }
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &callees,
- -1);
-
- sysprof_memprof_page_update_descendants (self, callees);
-
- callers_store = gtk_list_store_new (5,
- G_TYPE_STRING,
- G_TYPE_DOUBLE,
- G_TYPE_DOUBLE,
- G_TYPE_POINTER,
- G_TYPE_UINT64);
-
- callers = g_hash_table_new_full (NULL, NULL, NULL, caller_free);
- processed = g_hash_table_new (NULL, NULL);
-
- for (node = callees; node != NULL; node = node->next)
- {
- Caller *c;
-
- if (!node->parent)
- continue;
-
- c = g_hash_table_lookup (callers, U64_TO_POINTER (node->parent->data));
-
- if (c == NULL)
- {
- c = caller_new (node->parent);
- g_hash_table_insert (callers, (gpointer)c->name, c);
- }
- }
-
- for (node = callees; node != NULL; node = node->next)
- {
- StackNode *top_caller = node->parent;
- StackNode *top_callee = node;
- StackNode *n;
- Caller *c;
-
- if (!node->parent)
- continue;
-
- /*
- * We could have a situation where the function was called in a
- * reentrant fashion, so we want to take the top-most match in the
- * stack.
- */
- for (n = node; n && n->parent; n = n->parent)
- {
- if (n->data == node->data && n->parent->data == node->parent->data)
- {
- top_caller = n->parent;
- top_callee = n;
- }
- }
-
- c = g_hash_table_lookup (callers, U64_TO_POINTER (node->parent->data));
-
- g_assert (c != NULL);
-
- if (!g_hash_table_lookup (processed, top_caller))
- {
- c->total += top_callee->total;
- g_hash_table_insert (processed, top_caller, top_caller);
- }
-
- c->self += node->size;
- }
-
- {
- GHashTableIter hiter;
- gpointer key, value;
- guint64 size = 0;
-
- size = MAX (1, sysprof_memprof_page_get_profile_size (self));
-
- g_hash_table_iter_init (&hiter, callers);
-
- while (g_hash_table_iter_next (&hiter, &key, &value))
- {
- Caller *c = value;
-
- gtk_list_store_append (callers_store, &iter);
- gtk_list_store_set (callers_store, &iter,
- COLUMN_NAME, c->name,
- COLUMN_SELF, c->self * 100.0 / size,
- COLUMN_TOTAL, c->total * 100.0 / size,
- COLUMN_POINTER, c->node,
- COLUMN_SIZE, (guint64)c->total,
- -1);
- }
- }
-
- gtk_tree_view_set_model (priv->callers_view, GTK_TREE_MODEL (callers_store));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (callers_store),
- COLUMN_TOTAL,
- GTK_SORT_DESCENDING);
-
- g_clear_object (&callers_store);
-}
-
-static void
-sysprof_memprof_page_set_node (SysprofMemprofPage *self,
- StackNode *node)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (node != NULL);
-
- if (priv->profile == NULL)
- return;
-
- model = gtk_tree_view_get_model (priv->functions_view);
-
- if (gtk_tree_model_get_iter_first (model, &iter))
- {
- do
- {
- StackNode *item = NULL;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &item,
- -1);
-
- if (item != NULL && item->data == node->data)
- {
- GtkTreeSelection *selection;
-
- selection = gtk_tree_view_get_selection (priv->functions_view);
- gtk_tree_selection_select_iter (selection, &iter);
-
- break;
- }
- }
- while (gtk_tree_model_iter_next (model, &iter));
- }
-}
-
-static void
-sysprof_memprof_page_descendant_activated (SysprofMemprofPage *self,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- GtkTreeView *tree_view)
-{
- GtkTreeModel *model;
- StackNode *node = NULL;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (GTK_IS_TREE_VIEW (tree_view));
- g_assert (path != NULL);
- g_assert (GTK_IS_TREE_VIEW_COLUMN (column));
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (!gtk_tree_model_get_iter (model, &iter, path))
- return;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &node,
- -1);
-
- if (node != NULL)
- sysprof_memprof_page_set_node (self, node);
-}
-
-static void
-sysprof_memprof_page_caller_activated (SysprofMemprofPage *self,
- GtkTreePath *path,
- GtkTreeViewColumn *column,
- GtkTreeView *tree_view)
-{
- GtkTreeModel *model;
- StackNode *node = NULL;
- GtkTreeIter iter;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (GTK_IS_TREE_VIEW (tree_view));
- g_assert (path != NULL);
- g_assert (GTK_IS_TREE_VIEW_COLUMN (column));
-
- model = gtk_tree_view_get_model (tree_view);
-
- if (!gtk_tree_model_get_iter (model, &iter, path))
- return;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_POINTER, &node,
- -1);
-
- if (node != NULL)
- sysprof_memprof_page_set_node (self, node);
-}
-
-static void
-sysprof_memprof_page_size_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- g_autofree gchar *size_str = NULL;
- guint64 size;
-
- gtk_tree_model_get (model, iter, COLUMN_SIZE, &size, -1);
- if (size)
- size_str = g_format_size_full (size, G_FORMAT_SIZE_IEC_UNITS);
- g_object_set (cell, "text", size_str, NULL);
-}
-
-static void
-sysprof_memprof_page_tag_data_func (GtkTreeViewColumn *column,
- GtkCellRenderer *cell,
- GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- SysprofMemprofPage *self = data;
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- StackNode *node = NULL;
- const gchar *str = NULL;
-
- if (priv->profile == NULL)
- return;
-
- gtk_tree_model_get (model, iter, COLUMN_POINTER, &node, -1);
-
- if (node && node->data)
- {
- GQuark tag;
-
- tag = sysprof_memprof_profile_get_tag (priv->profile, GSIZE_TO_POINTER (node->data));
- if (tag != 0)
- str = g_quark_to_string (tag);
- }
-
- g_object_set (cell, "text", str, NULL);
-}
-
-static void
-sysprof_memprof_page_real_go_previous (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- StackNode *node;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
-
- node = g_queue_pop_head (priv->history);
-
- if (NULL != (node = g_queue_peek_head (priv->history)))
- sysprof_memprof_page_set_node (self, node);
-}
-
-static void
-descendants_view_move_cursor_cb (GtkTreeView *descendants_view,
- GtkMovementStep step,
- int direction,
- gpointer user_data)
-{
- if (step == GTK_MOVEMENT_VISUAL_POSITIONS)
- {
- GtkTreePath *path;
-
- gtk_tree_view_get_cursor (descendants_view, &path, NULL);
-
- if (direction == 1)
- {
- gtk_tree_view_expand_row (descendants_view, path, FALSE);
- g_signal_stop_emission_by_name (descendants_view, "move-cursor");
- }
- else if (direction == -1)
- {
- gtk_tree_view_collapse_row (descendants_view, path);
- g_signal_stop_emission_by_name (descendants_view, "move-cursor");
- }
-
- gtk_tree_path_free (path);
- }
-}
-
-static void
-copy_tree_view_selection_cb (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- g_autofree gchar *name = NULL;
- g_autofree gchar *size_str = NULL;
- gchar tstr[16];
- GString *str = data;
- gdouble total;
- guint64 size;
- gint depth;
-
- g_assert (GTK_IS_TREE_MODEL (model));
- g_assert (path != NULL);
- g_assert (iter != NULL);
- g_assert (str != NULL);
-
- depth = gtk_tree_path_get_depth (path);
- gtk_tree_model_get (model, iter,
- COLUMN_NAME, &name,
- COLUMN_TOTAL, &total,
- COLUMN_SIZE, &size,
- -1);
-
- size_str = g_format_size_full (size, G_FORMAT_SIZE_IEC_UNITS);
- g_snprintf (tstr, sizeof tstr, "%.2lf%%", total);
-
- g_string_append_printf (str, "[%12s] [%8s] ", size_str, tstr);
-
- for (gint i = 1; i < depth; i++)
- g_string_append (str, " ");
- g_string_append (str, name);
- g_string_append_c (str, '\n');
-}
-
-static void
-copy_tree_view_selection (GtkTreeView *tree_view)
-{
- g_autoptr(GString) str = NULL;
- GdkClipboard *clipboard;
-
- g_assert (GTK_IS_TREE_VIEW (tree_view));
-
- str = g_string_new (" ALLOCATED TOTAL FUNCTION\n");
- gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree_view),
- copy_tree_view_selection_cb,
- str);
-
- clipboard = gtk_widget_get_clipboard (GTK_WIDGET (tree_view));
- gdk_clipboard_set_text (clipboard, str->str);
-}
-
-static void
-sysprof_memprof_page_copy_cb (GtkWidget *widget,
- const char *action_name,
- GVariant *param)
-{
- SysprofMemprofPage *self = (SysprofMemprofPage *)widget;
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkWidget *focus;
- GtkRoot *toplevel;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
-
- if (!(toplevel = gtk_widget_get_root (widget)) ||
- !GTK_IS_ROOT (toplevel) ||
- !(focus = gtk_root_get_focus (toplevel)))
- return;
-
- if (focus == GTK_WIDGET (priv->descendants_view))
- copy_tree_view_selection (priv->descendants_view);
- else if (focus == GTK_WIDGET (priv->callers_view))
- copy_tree_view_selection (priv->callers_view);
- else if (focus == GTK_WIDGET (priv->functions_view))
- copy_tree_view_selection (priv->functions_view);
-}
-
-static void
-sysprof_memprof_page_generate_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- SysprofProfile *profile = (SysprofProfile *)object;
- SysprofMemprofPage *self;
- g_autoptr(GTask) task = user_data;
- g_autoptr(GError) error = NULL;
-
- g_assert (SYSPROF_IS_PROFILE (profile));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (G_IS_TASK (task));
-
- self = g_task_get_source_object (task);
-
- if (!sysprof_profile_generate_finish (profile, result, &error))
- g_task_return_error (task, g_error_copy (error));
- else
- sysprof_memprof_page_set_profile (self, SYSPROF_MEMPROF_PROFILE (profile));
-}
-
-static void
-sysprof_memprof_page_load_async (SysprofPage *page,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *filter,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SysprofMemprofPage *self = (SysprofMemprofPage *)page;
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- g_autoptr(SysprofCaptureReader) copy = NULL;
- g_autoptr(SysprofProfile) profile = NULL;
- g_autoptr(GTask) task = NULL;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_SELECTION (selection));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- g_cancellable_cancel (priv->cancellable);
-
- if (cancellable == NULL)
- cancellable = priv->cancellable = g_cancellable_new ();
- else
- g_set_object (&priv->cancellable, cancellable);
-
- gtk_stack_set_visible_child (priv->stack, priv->loading_state);
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_memprof_page_load_async);
-
- copy = sysprof_capture_reader_copy (reader);
-
- profile = sysprof_memprof_profile_new_with_selection (selection);
- sysprof_memprof_profile_set_mode (SYSPROF_MEMPROF_PROFILE (profile), priv->mode);
- sysprof_profile_set_reader (profile, reader);
- sysprof_profile_generate (profile,
- cancellable,
- sysprof_memprof_page_generate_cb,
- g_steal_pointer (&task));
-}
-
-static gboolean
-sysprof_memprof_page_load_finish (SysprofPage *page,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_MEMPROF_PAGE (page), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
-
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-do_allocs (SysprofMemprofPage *self,
- SysprofMemprofMode mode)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
-
- priv->mode = mode;
- sysprof_page_reload (SYSPROF_PAGE (self));
-}
-
-static void
-mode_notify_active (SysprofMemprofPage *self,
- GParamSpec *pspec,
- GtkToggleButton *button)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
- g_assert (GTK_IS_TOGGLE_BUTTON (button));
-
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
- {
- if (button == priv->summary)
- do_allocs (self, SYSPROF_MEMPROF_MODE_SUMMARY);
- else if (button == priv->all_allocs)
- do_allocs (self, SYSPROF_MEMPROF_MODE_ALL_ALLOCS);
- else if (button == priv->temp_allocs)
- do_allocs (self, SYSPROF_MEMPROF_MODE_TEMP_ALLOCS);
- else if (button == priv->leaked_allocs_button)
- do_allocs (self, SYSPROF_MEMPROF_MODE_LEAKED_ALLOCS);
- }
-}
-
-static void
-sep_header_func (GtkListBoxRow *row,
- GtkListBoxRow *before,
- gpointer user_data)
-{
- if (before != NULL)
- gtk_list_box_row_set_header (row,
- g_object_new (GTK_TYPE_SEPARATOR,
- "orientation", GTK_ORIENTATION_HORIZONTAL,
- "visible", TRUE,
- NULL));
-}
-
-static void
-sysprof_memprof_page_finalize (GObject *object)
-{
- SysprofMemprofPage *self = (SysprofMemprofPage *)object;
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_clear_pointer (&priv->history, g_queue_free);
- g_clear_object (&priv->profile);
- g_clear_object (&priv->cancellable);
-
- G_OBJECT_CLASS (sysprof_memprof_page_parent_class)->finalize (object);
-}
-
-static void
-sysprof_memprof_page_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofMemprofPage *self = SYSPROF_MEMPROF_PAGE (object);
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- switch (prop_id)
- {
- case PROP_PROFILE:
- g_value_set_object (value, priv->profile);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_memprof_page_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofMemprofPage *self = SYSPROF_MEMPROF_PAGE (object);
-
- switch (prop_id)
- {
- case PROP_PROFILE:
- sysprof_memprof_page_set_profile (self, g_value_get_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_memprof_page_class_init (SysprofMemprofPageClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
-
- object_class->finalize = sysprof_memprof_page_finalize;
- object_class->get_property = sysprof_memprof_page_get_property;
- object_class->set_property = sysprof_memprof_page_set_property;
-
- page_class->load_async = sysprof_memprof_page_load_async;
- page_class->load_finish = sysprof_memprof_page_load_finish;
-
- klass->go_previous = sysprof_memprof_page_real_go_previous;
-
- properties [PROP_PROFILE] =
- g_param_spec_object ("profile",
- "Profile",
- "The callgraph profile to view",
- SYSPROF_TYPE_MEMPROF_PROFILE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- signals [GO_PREVIOUS] =
- g_signal_new ("go-previous",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (SysprofMemprofPageClass, go_previous),
- NULL, NULL, NULL, G_TYPE_NONE, 0);
-
- gtk_widget_class_set_template_from_resource (widget_class,
- "/org/gnome/sysprof/ui/sysprof-memprof-page.ui");
-
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, by_size);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, callers_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, function_size_cell);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, function_size_column);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, functions_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, descendants_view);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, descendants_name_column);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, stack);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, all_allocs);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, temp_allocs);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, summary);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, temp_allocs_count);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, num_allocs);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, leaked_allocs);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, leaked_allocs_button);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, loading_state);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, empty_state);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, summary_page);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofMemprofPage, callgraph);
-
- gtk_widget_class_install_action (widget_class, "page.copy", NULL, sysprof_memprof_page_copy_cb);
-
- gtk_widget_class_add_binding_action (widget_class, GDK_KEY_c, GDK_CONTROL_MASK, "page.copy", NULL);
- gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_Left, GDK_ALT_MASK, "go-previous", NULL);
-
- g_type_ensure (EGG_TYPE_PANED);
- g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_PERCENT);
-}
-
-static void
-sysprof_memprof_page_init (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeSelection *selection;
- GtkCellRenderer *cell;
-
- priv->history = g_queue_new ();
- priv->mode = SYSPROF_MEMPROF_MODE_ALL_ALLOCS;
-
- gtk_widget_init_template (GTK_WIDGET (self));
-
- gtk_stack_set_visible_child (priv->stack, priv->empty_state);
-
- gtk_list_box_set_header_func (priv->by_size, sep_header_func, NULL, NULL);
-
- g_signal_connect_object (priv->all_allocs,
- "notify::active",
- G_CALLBACK (mode_notify_active),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (priv->temp_allocs,
- "notify::active",
- G_CALLBACK (mode_notify_active),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (priv->leaked_allocs_button,
- "notify::active",
- G_CALLBACK (mode_notify_active),
- self,
- G_CONNECT_SWAPPED);
- g_signal_connect_object (priv->summary,
- "notify::active",
- G_CALLBACK (mode_notify_active),
- self,
- G_CONNECT_SWAPPED);
-
- selection = gtk_tree_view_get_selection (priv->functions_view);
-
- g_signal_connect_object (selection,
- "changed",
- G_CALLBACK (sysprof_memprof_page_function_selection_changed),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->descendants_view,
- "row-activated",
- G_CALLBACK (sysprof_memprof_page_descendant_activated),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->callers_view,
- "row-activated",
- G_CALLBACK (sysprof_memprof_page_caller_activated),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect (priv->descendants_view,
- "move-cursor",
- G_CALLBACK (descendants_view_move_cursor_cb),
- NULL);
-
- cell = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
- "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
- "xalign", 0.0f,
- NULL);
- gtk_tree_view_column_pack_start (priv->descendants_name_column, cell, TRUE);
- gtk_tree_view_column_add_attribute (priv->descendants_name_column, cell, "text", 0);
-
- cell = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
- "foreground", "#666666",
- "scale", PANGO_SCALE_SMALL,
- "xalign", 1.0f,
- NULL);
- gtk_tree_view_column_pack_start (priv->descendants_name_column, cell, FALSE);
- gtk_tree_view_column_set_cell_data_func (priv->descendants_name_column, cell,
- sysprof_memprof_page_tag_data_func,
- self, NULL);
-
- gtk_tree_view_column_set_cell_data_func (priv->function_size_column,
- GTK_CELL_RENDERER (priv->function_size_cell),
- sysprof_memprof_page_size_data_func,
- self, NULL);
-
- gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->descendants_view),
- GTK_SELECTION_MULTIPLE);
-}
-
-typedef struct _Descendant Descendant;
-
-struct _Descendant
-{
- const gchar *name;
- guint self;
- guint cumulative;
- Descendant *parent;
- Descendant *siblings;
- Descendant *children;
-};
-
-static void
-build_tree_cb (StackLink *trace,
- gint size,
- gpointer user_data)
-{
- Descendant **tree = user_data;
- Descendant *parent = NULL;
- StackLink *link;
-
- g_assert (trace != NULL);
- g_assert (tree != NULL);
-
- /* Get last item */
- link = trace;
- while (link->next)
- link = link->next;
-
- for (; link != NULL; link = link->prev)
- {
- const gchar *address = U64_TO_POINTER (link->data);
- Descendant *prev = NULL;
- Descendant *match = NULL;
-
- for (match = *tree; match != NULL; match = match->siblings)
- {
- if (match->name == address)
- {
- if (prev != NULL)
- {
- /* Move to front */
- prev->siblings = match->siblings;
- match->siblings = *tree;
- *tree = match;
- }
- break;
- }
- }
-
- if (match == NULL)
- {
- /* Have we seen this object further up the tree? */
- for (match = parent; match != NULL; match = match->parent)
- {
- if (match->name == address)
- break;
- }
- }
-
- if (match == NULL)
- {
- match = g_slice_new (Descendant);
- match->name = address;
- match->cumulative = 0;
- match->self = 0;
- match->children = NULL;
- match->parent = parent;
- match->siblings = *tree;
- *tree = match;
- }
-
- tree = &match->children;
- parent = match;
- }
-
- parent->self += size;
-
- for (; parent != NULL; parent = parent->parent)
- parent->cumulative += size;
-}
-
-static Descendant *
-build_tree (StackNode *node)
-{
- Descendant *tree = NULL;
-
- for (; node != NULL; node = node->next)
- {
- if (node->toplevel)
- stack_node_foreach_trace (node, build_tree_cb, &tree);
- }
-
- return tree;
-}
-
-static void
-append_to_tree_and_free (SysprofMemprofPage *self,
- StackStash *stash,
- GtkTreeStore *store,
- Descendant *item,
- GtkTreeIter *parent)
-{
- StackNode *node = NULL;
- GtkTreeIter iter;
- guint profile_size;
-
- g_assert (GTK_IS_TREE_STORE (store));
- g_assert (item != NULL);
-
- profile_size = MAX (1, sysprof_memprof_page_get_profile_size (self));
-
- gtk_tree_store_append (store, &iter, parent);
-
- node = stack_stash_find_node (stash, (gpointer)item->name);
-
- gtk_tree_store_set (store, &iter,
- COLUMN_NAME, item->name,
- COLUMN_SELF, item->self * 100.0 / (gdouble)profile_size,
- COLUMN_TOTAL, item->cumulative * 100.0 / (gdouble)profile_size,
- COLUMN_POINTER, node,
- COLUMN_SIZE, item->cumulative,
- -1);
-
- if (item->siblings != NULL)
- append_to_tree_and_free (self, stash, store, item->siblings, parent);
-
- if (item->children != NULL)
- append_to_tree_and_free (self, stash, store, item->children, &iter);
-
- g_slice_free (Descendant, item);
-}
-
-static void
-sysprof_memprof_page_update_descendants (SysprofMemprofPage *self,
- StackNode *node)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeStore *store;
-
- g_assert (SYSPROF_IS_MEMPROF_PAGE (self));
-
- if (g_queue_peek_head (priv->history) != node)
- g_queue_push_head (priv->history, node);
-
- store = gtk_tree_store_new (5,
- G_TYPE_STRING,
- G_TYPE_DOUBLE,
- G_TYPE_DOUBLE,
- G_TYPE_POINTER,
- G_TYPE_UINT64);
-
- if (priv->profile != NULL)
- {
- StackStash *stash;
-
- stash = sysprof_memprof_profile_get_stash (priv->profile);
- if (stash != NULL)
- {
- Descendant *tree;
-
- tree = build_tree (node);
- if (tree != NULL)
- append_to_tree_and_free (self, stash, store, tree, NULL);
- }
- }
-
- gtk_tree_view_set_model (priv->descendants_view, GTK_TREE_MODEL (store));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
- COLUMN_TOTAL, GTK_SORT_DESCENDING);
- sysprof_memprof_page_expand_descendants (self);
-
- g_clear_object (&store);
-}
-
-/**
- * sysprof_memprof_page_screenshot:
- * @self: A #SysprofMemprofPage.
- *
- * This function will generate a text representation of the descendants tree.
- * This is useful if you want to include various profiling information in a
- * commit message or email.
- *
- * The text generated will match the current row expansion in the tree view.
- *
- * Returns: (nullable) (transfer full): A newly allocated string that should be freed
- * with g_free().
- */
-gchar *
-sysprof_memprof_page_screenshot (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeView *tree_view;
- GtkTreeModel *model;
- GtkTreePath *tree_path;
- GString *str;
- GtkTreeIter iter;
-
- g_return_val_if_fail (SYSPROF_IS_MEMPROF_PAGE (self), NULL);
-
- tree_view = priv->descendants_view;
-
- if (NULL == (model = gtk_tree_view_get_model (tree_view)))
- return NULL;
-
- /*
- * To avoid having to precalculate the deepest visible row, we
- * put the timing information at the beginning of the line.
- */
-
- str = g_string_new (" SELF CUMULATIVE FUNCTION\n");
- tree_path = gtk_tree_path_new_first ();
-
- for (;;)
- {
- if (gtk_tree_model_get_iter (model, &iter, tree_path))
- {
- guint depth = gtk_tree_path_get_depth (tree_path);
- StackNode *node;
- gdouble in_self;
- gdouble total;
- guint i;
-
- gtk_tree_model_get (model, &iter,
- COLUMN_SELF, &in_self,
- COLUMN_TOTAL, &total,
- COLUMN_POINTER, &node,
- -1);
-
- g_string_append_printf (str, "[% 7.2lf%%] [% 7.2lf%%] ", in_self, total);
-
- for (i = 0; i < depth; i++)
- g_string_append (str, " ");
- g_string_append (str, GSIZE_TO_POINTER (node->data));
- g_string_append_c (str, '\n');
-
- if (gtk_tree_view_row_expanded (tree_view, tree_path))
- gtk_tree_path_down (tree_path);
- else
- gtk_tree_path_next (tree_path);
-
- continue;
- }
-
- if (!gtk_tree_path_up (tree_path) || !gtk_tree_path_get_depth (tree_path))
- break;
-
- gtk_tree_path_next (tree_path);
- }
-
- gtk_tree_path_free (tree_path);
-
- return g_string_free (str, FALSE);
-}
-
-guint
-sysprof_memprof_page_get_n_functions (SysprofMemprofPage *self)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
- GtkTreeModel *model;
- guint ret = 0;
-
- g_return_val_if_fail (SYSPROF_IS_MEMPROF_PAGE (self), 0);
-
- if (NULL != (model = gtk_tree_view_get_model (priv->functions_view)))
- ret = gtk_tree_model_iter_n_children (model, NULL);
-
- return ret;
-}
-
-void
-_sysprof_memprof_page_set_loading (SysprofMemprofPage *self,
- gboolean loading)
-{
- SysprofMemprofPagePrivate *priv = sysprof_memprof_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_MEMPROF_PAGE (self));
-
- if (loading)
- priv->loading++;
- else
- priv->loading--;
-
- if (priv->loading)
- gtk_stack_set_visible_child (priv->stack, priv->loading_state);
- else
- gtk_stack_set_visible_child (priv->stack, priv->callgraph);
-}
diff --git a/src/libsysprof-ui/sysprof-memprof-page.h b/src/libsysprof-ui/sysprof-memprof-page.h
deleted file mode 100644
index 1b3f7af3..00000000
--- a/src/libsysprof-ui/sysprof-memprof-page.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* sysprof-memprof-page.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-#include
-
-#include "sysprof-page.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_MEMPROF_PAGE (sysprof_memprof_page_get_type())
-
-G_DECLARE_DERIVABLE_TYPE (SysprofMemprofPage, sysprof_memprof_page, SYSPROF, MEMPROF_PAGE, SysprofPage)
-
-struct _SysprofMemprofPageClass
-{
- SysprofPageClass parent_class;
-
- void (*go_previous) (SysprofMemprofPage *self);
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-GtkWidget *sysprof_memprof_page_new (void);
-SysprofMemprofProfile *sysprof_memprof_page_get_profile (SysprofMemprofPage *self);
-void sysprof_memprof_page_set_profile (SysprofMemprofPage *self,
- SysprofMemprofProfile *profile);
-gchar *sysprof_memprof_page_screenshot (SysprofMemprofPage *self);
-guint sysprof_memprof_page_get_n_functions (SysprofMemprofPage *self);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-memprof-page.ui b/src/libsysprof-ui/sysprof-memprof-page.ui
deleted file mode 100644
index ca22240a..00000000
--- a/src/libsysprof-ui/sysprof-memprof-page.ui
+++ /dev/null
@@ -1,330 +0,0 @@
-
-
-
-
-
- vertical
-
-
-
-
-
-
-
-
- false
- Number of Allocations
- Total number of allocation and free records
-
-
- true
- 1
- true
-
-
-
-
-
-
- false
- Leaked Allocations
- Number of allocations without a free record
-
-
- true
- 1
- true
-
-
-
-
-
-
- false
- Temporary Allocations
- Number of allocations freed from similar stack trace
-
-
- true
- 1
- true
-
-
-
-
-
-
-
-
- Allocations by Size
-
-
-
-
-
-
-
-
-
-
-
- horizontal
- true
-
-
- 400
- vertical
-
-
- true
-
-
- true
-
-
- true
- fixed
- 0
- Functions
-
-
- middle
-
-
- 0
-
-
-
-
-
-
- false
- false
- fixed
- 1
- Self
-
-
- 65
-
-
- 1
-
-
-
-
-
-
- false
- fixed
- 2
- Total
-
-
- 65
-
-
- 2
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
-
- true
- fixed
- 0
- Callers
-
-
- middle
-
-
- 0
-
-
-
-
-
-
- false
- false
- fixed
- 1
- Self
-
-
- 65
-
-
- 1
-
-
-
-
-
-
- false
- fixed
- 2
- Total
-
-
- 65
-
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- autosize
- 0
- Descendants
-
-
-
-
- false
- false
- fixed
- 1
- Self
-
-
- 65
-
-
- 1
-
-
-
-
-
-
- false
- fixed
- 2
- Total
-
-
- 65
-
-
- 2
-
-
-
-
-
-
- false
- fixed
- Size
-
-
- 1.0
-
-
-
-
-
-
-
-
-
-
-
-
- content-loading-symbolic
- Analyzing Memory Allocations
- Sysprof is busy analyzing memory allocations.
-
-
-
-
- computer-fail-symbolic
- Not Enough Samples
- More samples are necessary to display a callgraph.
-
-
-
-
-
-
- horizontal
-
-
-
-
- horizontal
-
-
- 6
- 6
- 6
- 6
- horizontal
- true
-
-
-
- Summary
- false
-
-
-
-
- All Allocations
- summary
- true
-
-
-
-
- Temporary Allocations
- false
- summary
-
-
-
-
- Leaked Allocations
- false
- summary
-
-
-
-
-
-
-
-
-
-
diff --git a/src/libsysprof-ui/sysprof-memprof-visualizer.c b/src/libsysprof-ui/sysprof-memprof-visualizer.c
deleted file mode 100644
index a117dd7f..00000000
--- a/src/libsysprof-ui/sysprof-memprof-visualizer.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/* sysprof-memprof-visualizer.c
- *
- * Copyright 2020 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "config.h"
-
-#define G_LOG_DOMAIN "sysprof-memprof-visualizer"
-
-#include
-#include
-#include
-
-#include "rax.h"
-
-#include "sysprof-memprof-visualizer.h"
-
-typedef struct
-{
- cairo_surface_t *surface;
- SysprofCaptureReader *reader;
- rax *rax;
- GtkAllocation alloc;
- gint64 begin_time;
- gint64 duration;
- gint64 total_alloc;
- gint64 max_alloc;
- GdkRGBA fg;
- GdkRGBA fg2;
- guint scale;
-} DrawContext;
-
-struct _SysprofMemprofVisualizer
-{
- SysprofVisualizer parent_instance;
-
- SysprofCaptureReader *reader;
- GCancellable *cancellable;
-
- cairo_surface_t *surface;
- gint surface_w;
- gint surface_h;
-
- guint queued_draw;
-
- gint64 begin_time;
- gint64 duration;
-
- gint64 cached_total_alloc;
- gint64 cached_max_alloc;
-
- guint mode : 1;
-};
-
-enum {
- MODE_ALLOCS,
- MODE_TOTAL,
-};
-
-G_DEFINE_TYPE (SysprofMemprofVisualizer, sysprof_memprof_visualizer, SYSPROF_TYPE_VISUALIZER)
-
-static void
-draw_context_free (DrawContext *draw)
-{
- g_clear_pointer (&draw->reader, sysprof_capture_reader_unref);
- g_clear_pointer (&draw->surface, cairo_surface_destroy);
- g_clear_pointer (&draw->rax, raxFree);
- g_slice_free (DrawContext, draw);
-}
-
-static void
-sysprof_memprof_visualizer_set_reader (SysprofVisualizer *visualizer,
- SysprofCaptureReader *reader)
-{
- SysprofMemprofVisualizer *self = (SysprofMemprofVisualizer *)visualizer;
-
- g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
-
- if (reader == self->reader)
- return;
-
- g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
-
- self->reader = sysprof_capture_reader_ref (reader);
- self->begin_time = sysprof_capture_reader_get_start_time (reader);
- self->duration = sysprof_capture_reader_get_end_time (reader)
- - sysprof_capture_reader_get_start_time (reader);
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
-}
-
-SysprofVisualizer *
-sysprof_memprof_visualizer_new (gboolean total_allocs)
-{
- SysprofMemprofVisualizer *self;
-
- self = g_object_new (SYSPROF_TYPE_MEMPROF_VISUALIZER,
- "title", total_allocs ? _("Memory Used") : _("Memory Allocations"),
- "height-request", 35,
- "visible", TRUE,
- NULL);
-
- if (total_allocs)
- self->mode = MODE_TOTAL;
- else
- self->mode = MODE_ALLOCS;
-
- return SYSPROF_VISUALIZER (self);
-}
-
-static guint64
-get_max_alloc (SysprofCaptureReader *reader)
-{
- SysprofCaptureFrameType type;
- gint64 ret = 0;
-
- while (sysprof_capture_reader_peek_type (reader, &type))
- {
- const SysprofCaptureAllocation *ev;
-
- if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
- {
- if (!(ev = sysprof_capture_reader_read_allocation (reader)))
- break;
-
- if (ev->alloc_size > ret)
- ret = ev->alloc_size;
- }
- else
- {
- if (!sysprof_capture_reader_skip (reader))
- break;
- continue;
- }
- }
-
- sysprof_capture_reader_reset (reader);
-
- return ret;
-}
-
-static guint64
-get_total_alloc (SysprofCaptureReader *reader)
-{
- SysprofCaptureFrameType type;
- guint64 total = 0;
- guint64 max = 0;
- rax *r;
-
- r = raxNew ();
-
- while (sysprof_capture_reader_peek_type (reader, &type))
- {
- const SysprofCaptureAllocation *ev;
-
- if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
- {
- if (!(ev = sysprof_capture_reader_read_allocation (reader)))
- break;
-
- if (ev->alloc_size > 0)
- {
- raxInsert (r,
- (guint8 *)&ev->alloc_addr,
- sizeof ev->alloc_addr,
- GSIZE_TO_POINTER (ev->alloc_size),
- NULL);
-
- total += ev->alloc_size;
-
- if (total > max)
- max = total;
- }
- else
- {
- gpointer res = raxFind (r, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr);
-
- if (res != raxNotFound)
- {
- total -= GPOINTER_TO_SIZE (res);
- raxRemove (r,
- (guint8 *)&ev->alloc_addr,
- sizeof ev->alloc_addr,
- NULL);
- }
- }
- }
- else
- {
- if (!sysprof_capture_reader_skip (reader))
- break;
- continue;
- }
- }
-
- sysprof_capture_reader_reset (reader);
- raxFree (r);
-
- return max;
-}
-
-static void
-draw_total_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- SysprofCaptureFrameType type;
- DrawContext *draw = task_data;
- gint64 total = 0;
- cairo_t *cr;
- rax *r;
- gint x = 0;
-
- g_assert (G_IS_TASK (task));
- g_assert (draw != NULL);
- g_assert (draw->surface != NULL);
- g_assert (draw->reader != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- if (draw->total_alloc == 0)
- draw->total_alloc = get_total_alloc (draw->reader);
-
- r = raxNew ();
-
- /* To avoid sorting, this code assums that all allocation information
- * is sorted and in order. Generally this is the case, but a crafted
- * syscap file could break it on purpose if they tried.
- */
-
- cr = cairo_create (draw->surface);
- cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
- cairo_set_source_rgb (cr, 0, 0, 0);
-
- while (sysprof_capture_reader_peek_type (draw->reader, &type))
- {
- const SysprofCaptureAllocation *ev;
- gint y;
-
- if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
- {
- if (!(ev = sysprof_capture_reader_read_allocation (draw->reader)))
- break;
-
- if (ev->alloc_size > 0)
- {
- raxInsert (r,
- (guint8 *)&ev->alloc_addr,
- sizeof ev->alloc_addr,
- GSIZE_TO_POINTER (ev->alloc_size),
- NULL);
-
- total += ev->alloc_size;
- }
- else
- {
- gpointer res = raxFind (r, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr);
-
- if (res != raxNotFound)
- {
- total -= GPOINTER_TO_SIZE (res);
- raxRemove (r,
- (guint8 *)&ev->alloc_addr,
- sizeof ev->alloc_addr,
- NULL);
- }
- }
- }
- else
- {
- if (!sysprof_capture_reader_skip (draw->reader))
- break;
- continue;
- }
-
- x = (ev->frame.time - draw->begin_time) / (gdouble)draw->duration * draw->alloc.width;
- y = draw->alloc.height - ((gdouble)total / (gdouble)draw->total_alloc * (gdouble)draw->alloc.height);
-
- cairo_rectangle (cr, x, y, 1, 1);
- cairo_fill (cr);
- }
-
- cairo_destroy (cr);
-
- g_task_return_boolean (task, TRUE);
-
- raxFree (r);
-}
-
-static void
-draw_alloc_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- static const gdouble dashes[] = { 1.0, 2.0 };
- DrawContext *draw = task_data;
- SysprofCaptureFrameType type;
- GdkRGBA *last;
- GdkRGBA mid;
- cairo_t *cr;
- guint counter = 0;
- gint midpt;
- gdouble log_max;
-
- g_assert (G_IS_TASK (task));
- g_assert (draw != NULL);
- g_assert (draw->surface != NULL);
- g_assert (draw->reader != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- if (draw->max_alloc == 0)
- draw->max_alloc = get_max_alloc (draw->reader);
-
- log_max = log10 (draw->max_alloc);
- midpt = draw->alloc.height / 2;
-
- cr = cairo_create (draw->surface);
-
- /* Draw mid-point line */
- mid = draw->fg;
- mid.alpha *= 0.4;
- cairo_set_line_width (cr, 1.0);
- gdk_cairo_set_source_rgba (cr, &mid);
- cairo_move_to (cr, 0, midpt);
- cairo_line_to (cr, draw->alloc.width, midpt);
- cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
- cairo_stroke (cr);
-
- cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
- gdk_cairo_set_source_rgba (cr, &draw->fg);
- last = &draw->fg;
-
- /* Now draw data points */
- while (sysprof_capture_reader_peek_type (draw->reader, &type))
- {
- const SysprofCaptureAllocation *ev;
- gint64 size;
- gdouble l;
- gint x;
- gint y;
-
- /* Cancellation check every 1000 frames */
- if G_UNLIKELY (++counter == 1000)
- {
- if (g_task_return_error_if_cancelled (task))
- {
- cairo_destroy (cr);
- return;
- }
-
- counter = 0;
- }
-
- /* We only care about memory frames here */
- if (type != SYSPROF_CAPTURE_FRAME_ALLOCATION)
- {
- if (!sysprof_capture_reader_skip (draw->reader))
- break;
- continue;
- }
-
- if (!(ev = sysprof_capture_reader_read_allocation (draw->reader)))
- break;
-
- if (ev->alloc_size > 0)
- {
- size = ev->alloc_size;
- raxInsert (draw->rax, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr, GSIZE_TO_POINTER (size), NULL);
-
- if (last != &draw->fg)
- {
- gdk_cairo_set_source_rgba (cr, &draw->fg);
- last = &draw->fg;
- }
- }
- else
- {
- size = GPOINTER_TO_SIZE (raxFind (draw->rax, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr));
- if (size)
- raxRemove (draw->rax, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr, NULL);
-
- if (last != &draw->fg2)
- {
- gdk_cairo_set_source_rgba (cr, &draw->fg2);
- last = &draw->fg2;
- }
- }
-
- l = log10 (size);
-
- x = (ev->frame.time - draw->begin_time) / (gdouble)draw->duration * draw->alloc.width;
-
- if (ev->alloc_size > 0)
- y = midpt - ((l / log_max) * midpt);
- else
- y = midpt + ((l / log_max) * midpt);
-
- /* Fill immediately instead of batching draws so that
- * we don't take a lot of memory to hold on to the
- * path while drawing.
- */
- cairo_rectangle (cr, x, y, 1, 1);
- cairo_fill (cr);
- }
-
- cairo_destroy (cr);
-
- g_task_return_boolean (task, TRUE);
-}
-
-static void
-draw_finished (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- g_autoptr(SysprofMemprofVisualizer) self = user_data;
- g_autoptr(GError) error = NULL;
-
- g_assert (object == NULL);
- g_assert (G_IS_TASK (result));
- g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
-
- if (g_task_propagate_boolean (G_TASK (result), &error))
- {
- DrawContext *draw = g_task_get_task_data (G_TASK (result));
-
- g_clear_pointer (&self->surface, cairo_surface_destroy);
-
- self->surface = g_steal_pointer (&draw->surface);
- self->surface_w = draw->alloc.width;
- self->surface_h = draw->alloc.height;
- self->cached_max_alloc = draw->max_alloc;
- self->cached_total_alloc = draw->total_alloc;
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
- }
-}
-
-static gboolean
-sysprof_memprof_visualizer_begin_draw (SysprofMemprofVisualizer *self)
-{
- g_autoptr(GTask) task = NULL;
- GtkAllocation alloc;
- DrawContext *draw;
-
- g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
-
- self->queued_draw = 0;
-
- /* Make sure we even need to draw */
- gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
- if (self->reader == NULL ||
- !gtk_widget_get_visible (GTK_WIDGET (self)) ||
- !gtk_widget_get_mapped (GTK_WIDGET (self)) ||
- alloc.width == 0 || alloc.height == 0)
- return G_SOURCE_REMOVE;
-
- /* Some GPUs (Intel) cannot deal with graphics textures larger than
- * 8000x8000. So here we are going to cheat a bit and just use that as our
- * max, and scale when drawing. The biggest issue here is that long term we
- * need a tiling solution that lets us render lots of tiles and then draw
- * them as necessary.
- */
- if (alloc.width > 8000)
- alloc.width = 8000;
-
- draw = g_slice_new0 (DrawContext);
- draw->rax = raxNew ();
- draw->alloc.width = alloc.width;
- draw->alloc.height = alloc.height;
- draw->reader = sysprof_capture_reader_copy (self->reader);
- draw->begin_time = self->begin_time;
- draw->duration = self->duration;
- draw->scale = gtk_widget_get_scale_factor (GTK_WIDGET (self));
- draw->max_alloc = self->cached_max_alloc;
- draw->total_alloc = self->cached_total_alloc;
-
- gdk_rgba_parse (&draw->fg, "rgba(246,97,81,1)");
- gdk_rgba_parse (&draw->fg2, "rgba(245,194,17,1)");
-
- draw->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- alloc.width * draw->scale,
- alloc.height * draw->scale);
- cairo_surface_set_device_scale (draw->surface, draw->scale, draw->scale);
-
- g_cancellable_cancel (self->cancellable);
- g_clear_object (&self->cancellable);
- self->cancellable = g_cancellable_new ();
-
- task = g_task_new (NULL, self->cancellable, draw_finished, g_object_ref (self));
- g_task_set_source_tag (task, sysprof_memprof_visualizer_begin_draw);
- g_task_set_task_data (task, g_steal_pointer (&draw), (GDestroyNotify)draw_context_free);
-
- if (self->mode == MODE_ALLOCS)
- g_task_run_in_thread (task, draw_alloc_worker);
- else
- g_task_run_in_thread (task, draw_total_worker);
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-sysprof_memprof_visualizer_queue_redraw (SysprofMemprofVisualizer *self)
-{
- g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
-
- if (self->queued_draw == 0)
- self->queued_draw = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
- (GSourceFunc) sysprof_memprof_visualizer_begin_draw,
- g_object_ref (self),
- g_object_unref);
-}
-
-static void
-sysprof_memprof_visualizer_size_allocate (GtkWidget *widget,
- int width,
- int height,
- int baseline)
-{
- sysprof_memprof_visualizer_queue_redraw (SYSPROF_MEMPROF_VISUALIZER (widget));
-}
-
-static void
-sysprof_memprof_visualizer_dispose (GObject *object)
-{
- SysprofMemprofVisualizer *self = (SysprofMemprofVisualizer *)object;
-
- g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
- g_clear_pointer (&self->surface, cairo_surface_destroy);
- g_clear_handle_id (&self->queued_draw, g_source_remove);
-
- G_OBJECT_CLASS (sysprof_memprof_visualizer_parent_class)->dispose (object);
-}
-
-static void
-sysprof_memprof_visualizer_snapshot (GtkWidget *widget,
- GtkSnapshot *snapshot)
-{
- SysprofMemprofVisualizer *self = (SysprofMemprofVisualizer *)widget;
-
- g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
- g_assert (GTK_IS_SNAPSHOT (snapshot));
-
- GTK_WIDGET_CLASS (sysprof_memprof_visualizer_parent_class)->snapshot (widget, snapshot);
-
- if (self->surface != NULL)
- {
- cairo_t *cr;
- GtkAllocation alloc;
-
- gtk_widget_get_allocation (widget, &alloc);
-
- cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
-
- cairo_save (cr);
- cairo_rectangle (cr, 0, 0, alloc.width, alloc.height);
-
- /* We might be drawing an updated image in the background, and this
- * will take our current surface (which is the wrong size) and draw
- * it stretched to fit the allocation. That gives us *something* that
- * represents the end result even if it is a bit blurry in the mean
- * time. Allocators take a while to render anyway.
- */
- if (self->surface_w != alloc.width || self->surface_h != alloc.height)
- {
- cairo_scale (cr,
- (gdouble)alloc.width / (gdouble)self->surface_w,
- (gdouble)alloc.height / (gdouble)self->surface_h);
- }
-
- cairo_set_source_surface (cr, self->surface, 0, 0);
- cairo_paint (cr);
- cairo_restore (cr);
-
- cairo_destroy (cr);
- }
-}
-
-static void
-sysprof_memprof_visualizer_class_init (SysprofMemprofVisualizerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
-
- object_class->dispose = sysprof_memprof_visualizer_dispose;
-
- widget_class->snapshot = sysprof_memprof_visualizer_snapshot;
- widget_class->size_allocate = sysprof_memprof_visualizer_size_allocate;
-
- visualizer_class->set_reader = sysprof_memprof_visualizer_set_reader;
-}
-
-static void
-sysprof_memprof_visualizer_init (SysprofMemprofVisualizer *self)
-{
-}
diff --git a/src/libsysprof-ui/sysprof-memprof-visualizer.h b/src/libsysprof-ui/sysprof-memprof-visualizer.h
deleted file mode 100644
index 04f078c8..00000000
--- a/src/libsysprof-ui/sysprof-memprof-visualizer.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* sysprof-memprof-visualizer.h
- *
- * Copyright 2020 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-visualizer.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_MEMPROF_VISUALIZER (sysprof_memprof_visualizer_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofMemprofVisualizer, sysprof_memprof_visualizer, SYSPROF, MEMPROF_VISUALIZER, SysprofVisualizer)
-
-SysprofVisualizer *sysprof_memprof_visualizer_new (gboolean total_allocs);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-model-filter.c b/src/libsysprof-ui/sysprof-model-filter.c
deleted file mode 100644
index 48c9386e..00000000
--- a/src/libsysprof-ui/sysprof-model-filter.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/* sysprof-model-filter.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "config.h"
-
-#include "sysprof-model-filter.h"
-
-typedef struct
-{
- GSequenceIter *child_iter;
- GSequenceIter *filter_iter;
-} SysprofModelFilterItem;
-
-typedef struct
-{
- /* The list we are filtering */
- GListModel *child_model;
-
- /*
- * Both sequences point to the same SysprofModelFilterItem which
- * contains cross-referencing stable GSequenceIter pointers.
- * The child_seq is considered the "owner" and used to release
- * allocated resources.
- */
- GSequence *child_seq;
- GSequence *filter_seq;
-
- /*
- * Typical set of callback/closure/free function pointers and data.
- * Called for child items to determine visibility state.
- */
- SysprofModelFilterFunc filter_func;
- gpointer filter_func_data;
- GDestroyNotify filter_func_data_destroy;
-
- /*
- * If set, we will not emit items-changed. This is useful during
- * invalidation so that we can do a single emission for all items
- * that have changed.
- */
- guint supress_items_changed : 1;
-} SysprofModelFilterPrivate;
-
-static void list_model_iface_init (GListModelInterface *iface);
-
-G_DEFINE_TYPE_EXTENDED (SysprofModelFilter, sysprof_model_filter, G_TYPE_OBJECT, 0,
- G_ADD_PRIVATE (SysprofModelFilter)
- G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
- list_model_iface_init))
-
-enum {
- PROP_0,
- PROP_CHILD_MODEL,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-static guint signal_id;
-
-static void
-sysprof_model_filter_item_free (gpointer data)
-{
- SysprofModelFilterItem *item = data;
-
- g_clear_pointer (&item->filter_iter, g_sequence_remove);
- item->child_iter = NULL;
- g_slice_free (SysprofModelFilterItem, item);
-}
-
-static gboolean
-sysprof_model_filter_default_filter_func (GObject *item,
- gpointer user_data)
-{
- return TRUE;
-}
-
-/*
- * Locates the next item in the filter sequence starting from
- * the cross-reference found at @iter. If none are found, the
- * end_iter for the filter sequence is returned.
- *
- * This returns an iter in the filter_sequence, not the child_seq.
- *
- * Returns: a #GSequenceIter from the filter sequence.
- */
-static GSequenceIter *
-find_next_visible_filter_iter (SysprofModelFilter *self,
- GSequenceIter *iter)
-{
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MODEL_FILTER (self));
- g_assert (iter != NULL);
-
- for (; !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
- {
- SysprofModelFilterItem *item = g_sequence_get (iter);
-
- g_assert (item->child_iter == iter);
- g_assert (item->filter_iter == NULL ||
- g_sequence_iter_get_sequence (item->filter_iter) == priv->filter_seq);
-
- if (item->filter_iter != NULL)
- return item->filter_iter;
- }
-
- return g_sequence_get_end_iter (priv->filter_seq);
-}
-
-static void
-sysprof_model_filter_child_model_items_changed (SysprofModelFilter *self,
- guint position,
- guint n_removed,
- guint n_added,
- GListModel *child_model)
-{
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
- gboolean unblocked;
-
- g_assert (SYSPROF_IS_MODEL_FILTER (self));
- g_assert (G_IS_LIST_MODEL (child_model));
- g_assert (priv->child_model == child_model);
- g_assert (position <= (guint)g_sequence_get_length (priv->child_seq));
- g_assert ((g_sequence_get_length (priv->child_seq) - n_removed + n_added) ==
- g_list_model_get_n_items (child_model));
-
- unblocked = !priv->supress_items_changed;
-
- if (n_removed > 0)
- {
- GSequenceIter *iter = g_sequence_get_iter_at_pos (priv->child_seq, position);
- gint first_position = -1;
- guint count = 0;
-
- g_assert (!g_sequence_iter_is_end (iter));
-
- /* Small shortcut when all items are removed */
- if (n_removed == (guint)g_sequence_get_length (priv->child_seq))
- {
- g_sequence_remove_range (g_sequence_get_begin_iter (priv->child_seq),
- g_sequence_get_end_iter (priv->child_seq));
- g_assert (g_sequence_is_empty (priv->child_seq));
- g_assert (g_sequence_is_empty (priv->filter_seq));
- goto add_new_items;
- }
-
- for (guint i = 0; i < n_removed; i++)
- {
- GSequenceIter *to_remove = iter;
- SysprofModelFilterItem *item = g_sequence_get (iter);
-
- g_assert (item != NULL);
- g_assert (item->child_iter == iter);
- g_assert (item->filter_iter == NULL ||
- g_sequence_iter_get_sequence (item->filter_iter) == priv->filter_seq);
-
- /* If this is visible, we need to notify about removal */
- if (unblocked && item->filter_iter != NULL)
- {
- if (first_position < 0)
- first_position = g_sequence_iter_get_position (item->filter_iter);
-
- count++;
- }
-
- /* Fetch the next while the iter is still valid */
- iter = g_sequence_iter_next (iter);
-
- /* Cascades into also removing from filter_seq. */
- g_sequence_remove (to_remove);
- }
-
- if (unblocked && first_position >= 0)
- g_list_model_items_changed (G_LIST_MODEL (self), first_position, count, 0);
- }
-
-add_new_items:
-
- if (n_added > 0)
- {
- GSequenceIter *iter = g_sequence_get_iter_at_pos (priv->child_seq, position);
- GSequenceIter *filter_iter = find_next_visible_filter_iter (self, iter);
- guint filter_position = g_sequence_iter_get_position (filter_iter);
- guint count = 0;
-
- /* Walk backwards to insert items into the filter list so that
- * we can use the same filter_position for each items-changed
- * signal emission.
- */
- for (guint i = position + n_added; i > position; i--)
- {
- g_autoptr(GObject) instance = NULL;
- SysprofModelFilterItem *item;
-
- item = g_slice_new0 (SysprofModelFilterItem);
- item->filter_iter = NULL;
- item->child_iter = g_sequence_insert_before (iter, item);
-
- instance = g_list_model_get_item (child_model, i - 1);
- g_assert (G_IS_OBJECT (instance));
-
- /* Check if this item is visible */
- if (priv->filter_func (instance, priv->filter_func_data))
- {
- item->filter_iter = g_sequence_insert_before (filter_iter, item);
-
- /* Use this in the future for relative positioning */
- filter_iter = item->filter_iter;
-
- count++;
- }
-
- /* Insert next item before this */
- iter = item->child_iter;
- }
-
- if (unblocked && count)
- g_list_model_items_changed (G_LIST_MODEL (self), filter_position, 0, count);
- }
-
- g_assert ((guint)g_sequence_get_length (priv->child_seq) ==
- g_list_model_get_n_items (child_model));
-}
-
-static void
-sysprof_model_filter_finalize (GObject *object)
-{
- SysprofModelFilter *self = (SysprofModelFilter *)object;
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- g_clear_pointer (&priv->child_seq, g_sequence_free);
- g_clear_pointer (&priv->filter_seq, g_sequence_free);
-
- if (priv->filter_func_data_destroy)
- {
- g_clear_pointer (&priv->filter_func_data, priv->filter_func_data_destroy);
- priv->filter_func_data_destroy = NULL;
- }
-
- g_clear_object (&priv->child_model);
-
- G_OBJECT_CLASS (sysprof_model_filter_parent_class)->finalize (object);
-}
-
-static void
-sysprof_model_filter_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofModelFilter *self = SYSPROF_MODEL_FILTER (object);
-
- switch (prop_id)
- {
- case PROP_CHILD_MODEL:
- g_value_set_object (value, sysprof_model_filter_get_child_model (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_model_filter_class_init (SysprofModelFilterClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = sysprof_model_filter_finalize;
- object_class->get_property = sysprof_model_filter_get_property;
-
- properties [PROP_CHILD_MODEL] =
- g_param_spec_object ("child-model",
- "Child Model",
- "The child model being filtered.",
- G_TYPE_LIST_MODEL,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- signal_id = g_signal_lookup ("items-changed", SYSPROF_TYPE_MODEL_FILTER);
-}
-
-static void
-sysprof_model_filter_init (SysprofModelFilter *self)
-{
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- priv->filter_func = sysprof_model_filter_default_filter_func;
- priv->child_seq = g_sequence_new (sysprof_model_filter_item_free);
- priv->filter_seq = g_sequence_new (NULL);
-}
-
-static GType
-sysprof_model_filter_get_item_type (GListModel *model)
-{
- SysprofModelFilter *self = (SysprofModelFilter *)model;
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MODEL_FILTER (self));
-
- return g_list_model_get_item_type (priv->child_model);
-}
-
-static guint
-sysprof_model_filter_get_n_items (GListModel *model)
-{
- SysprofModelFilter *self = (SysprofModelFilter *)model;
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- g_assert (SYSPROF_IS_MODEL_FILTER (self));
- g_assert (priv->filter_seq != NULL);
-
- return g_sequence_get_length (priv->filter_seq);
-}
-
-static gpointer
-sysprof_model_filter_get_item (GListModel *model,
- guint position)
-{
- SysprofModelFilter *self = (SysprofModelFilter *)model;
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
- SysprofModelFilterItem *item;
- GSequenceIter *iter;
- guint child_position;
-
- g_assert (SYSPROF_IS_MODEL_FILTER (self));
- g_assert (position < (guint)g_sequence_get_length (priv->filter_seq));
-
- iter = g_sequence_get_iter_at_pos (priv->filter_seq, position);
- g_assert (!g_sequence_iter_is_end (iter));
-
- item = g_sequence_get (iter);
- g_assert (item != NULL);
- g_assert (item->filter_iter == iter);
- g_assert (item->child_iter != NULL);
- g_assert (g_sequence_iter_get_sequence (item->child_iter) == priv->child_seq);
-
- child_position = g_sequence_iter_get_position (item->child_iter);
-
- return g_list_model_get_item (priv->child_model, child_position);
-}
-
-static void
-list_model_iface_init (GListModelInterface *iface)
-{
- iface->get_item_type = sysprof_model_filter_get_item_type;
- iface->get_n_items = sysprof_model_filter_get_n_items;
- iface->get_item = sysprof_model_filter_get_item;
-}
-
-SysprofModelFilter *
-sysprof_model_filter_new (GListModel *child_model)
-{
- SysprofModelFilter *ret;
- SysprofModelFilterPrivate *priv;
-
- g_return_val_if_fail (G_IS_LIST_MODEL (child_model), NULL);
-
- ret = g_object_new (SYSPROF_TYPE_MODEL_FILTER, NULL);
- priv = sysprof_model_filter_get_instance_private (ret);
- priv->child_model = g_object_ref (child_model);
-
- g_signal_connect_object (child_model,
- "items-changed",
- G_CALLBACK (sysprof_model_filter_child_model_items_changed),
- ret,
- G_CONNECT_SWAPPED);
-
- sysprof_model_filter_invalidate (ret);
-
- return ret;
-}
-
-/**
- * sysprof_model_filter_get_child_model:
- * @self: A #SysprofModelFilter
- *
- * Gets the child model that is being filtered.
- *
- * Returns: (transfer none): A #GListModel.
- */
-GListModel *
-sysprof_model_filter_get_child_model (SysprofModelFilter *self)
-{
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_MODEL_FILTER (self), NULL);
-
- return priv->child_model;
-}
-
-void
-sysprof_model_filter_invalidate (SysprofModelFilter *self)
-{
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
- guint n_items;
-
- g_return_if_fail (SYSPROF_IS_MODEL_FILTER (self));
-
- /* We block emission while in invalidate so that we can use
- * a single larger items-changed rather lots of small emissions.
- */
- priv->supress_items_changed = TRUE;
-
- /* First determine how many items we need to synthesize as a removal */
- n_items = g_sequence_get_length (priv->filter_seq);
-
- /*
- * If we have a child store, we want to rebuild our list of items
- * from scratch, so just remove everything.
- */
- if (!g_sequence_is_empty (priv->child_seq))
- g_sequence_remove_range (g_sequence_get_begin_iter (priv->child_seq),
- g_sequence_get_end_iter (priv->child_seq));
-
- g_assert (g_sequence_is_empty (priv->child_seq));
- g_assert (g_sequence_is_empty (priv->filter_seq));
- g_assert (!priv->child_model || G_IS_LIST_MODEL (priv->child_model));
-
- /*
- * Now add the new items by synthesizing the addition of all the
- * itmes in the list.
- */
- if (priv->child_model != NULL)
- {
- guint child_n_items;
-
- /*
- * Now add all the items as one shot to our list so that
- * we get populate our sequence and filter sequence.
- */
- child_n_items = g_list_model_get_n_items (priv->child_model);
- sysprof_model_filter_child_model_items_changed (self, 0, 0, child_n_items, priv->child_model);
-
- g_assert ((guint)g_sequence_get_length (priv->child_seq) == child_n_items);
- g_assert ((guint)g_sequence_get_length (priv->filter_seq) <= child_n_items);
- }
-
- priv->supress_items_changed = FALSE;
-
- /* Now that we've updated our sequences, notify of all the changes
- * as a single series of updates to the consumers.
- */
- if (n_items > 0 || !g_sequence_is_empty (priv->filter_seq))
- g_list_model_items_changed (G_LIST_MODEL (self),
- 0,
- n_items,
- g_sequence_get_length (priv->filter_seq));
-}
-
-void
-sysprof_model_filter_set_filter_func (SysprofModelFilter *self,
- SysprofModelFilterFunc filter_func,
- gpointer filter_func_data,
- GDestroyNotify filter_func_data_destroy)
-{
- SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_MODEL_FILTER (self));
- g_return_if_fail (filter_func || (!filter_func_data && !filter_func_data_destroy));
-
- if (priv->filter_func_data_destroy != NULL)
- g_clear_pointer (&priv->filter_func_data, priv->filter_func_data_destroy);
-
- if (filter_func != NULL)
- {
- priv->filter_func = filter_func;
- priv->filter_func_data = filter_func_data;
- priv->filter_func_data_destroy = filter_func_data_destroy;
- }
- else
- {
- priv->filter_func = sysprof_model_filter_default_filter_func;
- priv->filter_func_data = NULL;
- priv->filter_func_data_destroy = NULL;
- }
-
- sysprof_model_filter_invalidate (self);
-}
diff --git a/src/libsysprof-ui/sysprof-model-filter.h b/src/libsysprof-ui/sysprof-model-filter.h
deleted file mode 100644
index a1b97bd4..00000000
--- a/src/libsysprof-ui/sysprof-model-filter.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* sysprof-model-filter.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
-# error "Only can be included directly."
-#endif
-
-#include
-
-#include "sysprof-version-macros.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_MODEL_FILTER (sysprof_model_filter_get_type())
-
-typedef gboolean (*SysprofModelFilterFunc) (GObject *object,
- gpointer user_data);
-
-SYSPROF_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE (SysprofModelFilter, sysprof_model_filter, SYSPROF, MODEL_FILTER, GObject)
-
-struct _SysprofModelFilterClass
-{
- GObjectClass parent_class;
-
- gpointer padding[8];
-};
-
-SYSPROF_AVAILABLE_IN_ALL
-SysprofModelFilter *sysprof_model_filter_new (GListModel *child_model);
-SYSPROF_AVAILABLE_IN_ALL
-GListModel *sysprof_model_filter_get_child_model (SysprofModelFilter *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_model_filter_invalidate (SysprofModelFilter *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_model_filter_set_filter_func (SysprofModelFilter *self,
- SysprofModelFilterFunc filter_func,
- gpointer filter_func_data,
- GDestroyNotify filter_func_data_destroy);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-netdev-aid.c b/src/libsysprof-ui/sysprof-netdev-aid.c
deleted file mode 100644
index 5f1c9f2c..00000000
--- a/src/libsysprof-ui/sysprof-netdev-aid.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/* sysprof-netdev-aid.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-netdev-aid"
-
-#include "config.h"
-
-#include
-
-#include "sysprof-color-cycle.h"
-#include "sysprof-duplex-visualizer.h"
-#include "sysprof-netdev-aid.h"
-
-struct _SysprofNetdevAid
-{
- SysprofAid parent_instance;
-};
-
-typedef struct
-{
- SysprofCaptureCursor *cursor;
- SysprofDisplay *display;
-} Present;
-
-G_DEFINE_TYPE (SysprofNetdevAid, sysprof_netdev_aid, SYSPROF_TYPE_AID)
-
-static void
-present_free (gpointer data)
-{
- Present *p = data;
-
- g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
- g_clear_object (&p->display);
- g_slice_free (Present, p);
-}
-
-/**
- * sysprof_netdev_aid_new:
- *
- * Create a new #SysprofNetdevAid.
- *
- * Returns: (transfer full): a newly created #SysprofNetdevAid
- *
- * Since: 3.34
- */
-SysprofAid *
-sysprof_netdev_aid_new (void)
-{
- return g_object_new (SYSPROF_TYPE_NETDEV_AID, NULL);
-}
-
-static void
-sysprof_netdev_aid_prepare (SysprofAid *self,
- SysprofProfiler *profiler)
-{
- g_autoptr(SysprofSource) source = NULL;
-
- g_assert (SYSPROF_IS_NETDEV_AID (self));
- g_assert (SYSPROF_IS_PROFILER (profiler));
-
- source = sysprof_netdev_source_new ();
- sysprof_profiler_add_source (profiler, source);
-}
-
-static bool
-collect_netdev_counters (const SysprofCaptureFrame *frame,
- gpointer user_data)
-{
- SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
- GArray *counters = user_data;
-
- g_assert (frame != NULL);
- g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
- g_assert (counters != NULL);
-
- for (guint i = 0; i < def->n_counters; i++)
- {
- const SysprofCaptureCounter *counter = &def->counters[i];
-
- if (strcmp (counter->category, "Network") == 0 &&
- (g_str_has_prefix (counter->name, "RX Bytes") ||
- g_str_has_prefix (counter->name, "TX Bytes")))
- g_array_append_vals (counters, counter, 1);
- }
-
- return TRUE;
-}
-
-static void
-sysprof_netdev_aid_present_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- Present *present = task_data;
- g_autoptr(GArray) counters = NULL;
-
- g_assert (G_IS_TASK (task));
- g_assert (SYSPROF_IS_NETDEV_AID (source_object));
- g_assert (present != NULL);
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
- sysprof_capture_cursor_foreach (present->cursor, collect_netdev_counters, counters);
- g_task_return_pointer (task,
- g_steal_pointer (&counters),
- (GDestroyNotify) g_array_unref);
-}
-
-static guint
-find_other_id (GArray *counters,
- const gchar *rx)
-{
- g_autofree gchar *other = NULL;
-
- g_assert (counters);
- g_assert (rx != NULL);
-
- other = g_strdup (rx);
- other[0] = 'T';
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *c = &g_array_index (counters, SysprofCaptureCounter, i);
-
- if (g_str_equal (c->name, other))
- return c->id;
- }
-
- return 0;
-}
-
-static void
-sysprof_netdev_aid_present_async (SysprofAid *aid,
- SysprofCaptureReader *reader,
- SysprofDisplay *display,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
- g_autoptr(SysprofCaptureCondition) condition = NULL;
- g_autoptr(SysprofCaptureCursor) cursor = NULL;
- g_autoptr(GTask) task = NULL;
- Present present;
-
- g_assert (SYSPROF_IS_NETDEV_AID (aid));
- g_assert (reader != NULL);
- g_assert (SYSPROF_IS_DISPLAY (display));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- condition = sysprof_capture_condition_new_where_type_in (1, types);
- cursor = sysprof_capture_cursor_new (reader);
- sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
-
- present.cursor = g_steal_pointer (&cursor);
- present.display = g_object_ref (display);
-
- task = g_task_new (aid, cancellable, callback, user_data);
- g_task_set_source_tag (task, sysprof_netdev_aid_present_async);
- g_task_set_task_data (task,
- g_slice_dup (Present, &present),
- present_free);
- g_task_run_in_thread (task, sysprof_netdev_aid_present_worker);
-}
-
-static gboolean
-sysprof_netdev_aid_present_finish (SysprofAid *aid,
- GAsyncResult *result,
- GError **error)
-{
- g_autoptr(GArray) counters = NULL;
- Present *present;
-
- g_assert (SYSPROF_IS_AID (aid));
- g_assert (G_IS_TASK (result));
-
- present = g_task_get_task_data (G_TASK (result));
-
- if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
- {
- g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
- SysprofVisualizerGroup *group;
-
- group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
- "can-focus", TRUE,
- "title", _("Network"),
- "visible", TRUE,
- NULL);
-
- for (guint i = 0; i < counters->len; i++)
- {
- const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
-
- if (g_str_has_prefix (ctr->name, "RX Bytes"))
- {
- g_autofree gchar *title = NULL;
- gboolean is_combined;
- GtkWidget *row;
- GdkRGBA rgba;
- guint other_id;
-
- if (!(other_id = find_other_id (counters, ctr->name)))
- continue;
-
- is_combined = g_str_equal (ctr->description, "Combined");
-
- if (is_combined)
- title = g_strdup ("Network Bytes (All)");
- else
- title = g_strdup_printf ("Network Bytes%s", ctr->name + strlen ("RX Bytes"));
-
- row = g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER,
- "title", title,
- "height-request", 35,
- "visible", is_combined,
- NULL);
- sysprof_color_cycle_next (cycle, &rgba);
- sysprof_duplex_visualizer_set_counters (SYSPROF_DUPLEX_VISUALIZER (row), ctr->id, other_id);
- sysprof_duplex_visualizer_set_colors (SYSPROF_DUPLEX_VISUALIZER (row), &rgba, &rgba);
- sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), is_combined ? 0 : -1, !is_combined);
- }
- }
-
- if (counters->len > 0)
- sysprof_display_add_group (present->display, group);
- else
- g_object_unref (g_object_ref_sink (group));
- }
-
- return counters != NULL;
-}
-
-static void
-sysprof_netdev_aid_class_init (SysprofNetdevAidClass *klass)
-{
- SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
-
- aid_class->prepare = sysprof_netdev_aid_prepare;
- aid_class->present_async = sysprof_netdev_aid_present_async;
- aid_class->present_finish = sysprof_netdev_aid_present_finish;
-}
-
-static void
-sysprof_netdev_aid_init (SysprofNetdevAid *self)
-{
- sysprof_aid_set_display_name (SYSPROF_AID (self), _("Network"));
- sysprof_aid_set_icon_name (SYSPROF_AID (self), "preferences-system-network-symbolic");
-}
diff --git a/src/libsysprof-ui/sysprof-netdev-aid.h b/src/libsysprof-ui/sysprof-netdev-aid.h
deleted file mode 100644
index 6bff1765..00000000
--- a/src/libsysprof-ui/sysprof-netdev-aid.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* sysprof-netdev-aid.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include "sysprof-aid.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_NETDEV_AID (sysprof_netdev_aid_get_type())
-
-G_DECLARE_FINAL_TYPE (SysprofNetdevAid, sysprof_netdev_aid, SYSPROF, NETDEV_AID, SysprofAid)
-
-SysprofAid *sysprof_netdev_aid_new (void);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-notebook.c b/src/libsysprof-ui/sysprof-notebook.c
deleted file mode 100644
index 1a040c28..00000000
--- a/src/libsysprof-ui/sysprof-notebook.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/* sysprof-notebook.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-notebook"
-
-#include "config.h"
-
-#include "sysprof-display.h"
-#include "sysprof-notebook.h"
-#include "sysprof-tab.h"
-#include "sysprof-ui-private.h"
-
-typedef struct
-{
- GtkNotebook *notebook;
- guint always_show_tabs : 1;
-} SysprofNotebookPrivate;
-
-static void buildable_iface_init (GtkBuildableIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (SysprofNotebook, sysprof_notebook, GTK_TYPE_WIDGET,
- G_ADD_PRIVATE (SysprofNotebook)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
-
-enum {
- PROP_0,
- PROP_ALWAYS_SHOW_TABS,
- PROP_CAN_REPLAY,
- PROP_CAN_SAVE,
- PROP_CURRENT,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-/**
- * sysprof_notebook_new:
- *
- * Create a new #SysprofNotebook.
- *
- * Returns: (transfer full): a newly created #SysprofNotebook
- *
- * Since: 3.34
- */
-GtkWidget *
-sysprof_notebook_new (void)
-{
- return g_object_new (SYSPROF_TYPE_NOTEBOOK, NULL);
-}
-
-static void
-sysprof_notebook_notify_can_save_cb (SysprofNotebook *self,
- GParamSpec *pspec,
- SysprofDisplay *display)
-{
- g_assert (SYSPROF_IS_NOTEBOOK (self));
- g_assert (SYSPROF_IS_DISPLAY (display));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]);
-}
-
-static void
-sysprof_notebook_notify_can_replay_cb (SysprofNotebook *self,
- GParamSpec *pspec,
- SysprofDisplay *display)
-{
- g_assert (SYSPROF_IS_NOTEBOOK (self));
- g_assert (SYSPROF_IS_DISPLAY (display));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]);
-}
-
-static void
-sysprof_notebook_page_added (SysprofNotebook *self,
- GtkWidget *child,
- guint page_num,
- GtkNotebook *notebook)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_assert (SYSPROF_IS_NOTEBOOK (self));
- g_assert (GTK_IS_WIDGET (child));
- g_assert (GTK_IS_NOTEBOOK (notebook));
-
- gtk_notebook_set_show_tabs (notebook,
- (priv->always_show_tabs ||
- gtk_notebook_get_n_pages (notebook) > 1));
-
- if (SYSPROF_IS_DISPLAY (child))
- {
- GtkWidget *tab = sysprof_tab_new (SYSPROF_DISPLAY (child));
-
- gtk_notebook_set_tab_label (notebook, child, tab);
- gtk_notebook_set_tab_reorderable (notebook, child, TRUE);
-
- g_signal_connect_object (child,
- "notify::can-replay",
- G_CALLBACK (sysprof_notebook_notify_can_replay_cb),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (child,
- "notify::can-save",
- G_CALLBACK (sysprof_notebook_notify_can_save_cb),
- self,
- G_CONNECT_SWAPPED);
-
- g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_REPLAY]);
- g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CAN_SAVE]);
- g_object_notify_by_pspec (G_OBJECT (notebook), properties [PROP_CURRENT]);
-
- _sysprof_display_focus_record (SYSPROF_DISPLAY (child));
- }
-}
-
-static void
-sysprof_notebook_page_removed (SysprofNotebook *self,
- GtkWidget *child,
- guint page_num,
- GtkNotebook *notebook)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_assert (SYSPROF_IS_NOTEBOOK (self));
- g_assert (GTK_IS_WIDGET (child));
- g_assert (GTK_IS_NOTEBOOK (notebook));
-
- if (gtk_widget_in_destruction (GTK_WIDGET (notebook)))
- return;
-
- if (gtk_notebook_get_n_pages (notebook) == 0)
- {
- child = sysprof_display_new ();
- gtk_notebook_append_page (notebook, child, NULL);
- gtk_widget_show (child);
-
- g_signal_handlers_disconnect_by_func (child,
- G_CALLBACK (sysprof_notebook_notify_can_save_cb),
- notebook);
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CURRENT]);
- }
-
- gtk_notebook_set_show_tabs (notebook,
- (priv->always_show_tabs ||
- gtk_notebook_get_n_pages (notebook) > 1));
-}
-
-static void
-sysprof_notebook_switch_page (SysprofNotebook *self,
- GtkWidget *widget,
- guint page,
- GtkNotebook *notebook)
-{
- g_assert (SYSPROF_IS_NOTEBOOK (self));
- g_assert (GTK_IS_NOTEBOOK (notebook));
- g_assert (GTK_IS_WIDGET (widget));
-
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_REPLAY]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SAVE]);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CURRENT]);
-}
-
-static void
-sysprof_notebook_dispose (GObject *object)
-{
- SysprofNotebook *self = (SysprofNotebook *)object;
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- if (priv->notebook)
- {
- gtk_widget_unparent (GTK_WIDGET (priv->notebook));
- priv->notebook = NULL;
- }
-
- G_OBJECT_CLASS (sysprof_notebook_parent_class)->dispose (object);
-}
-
-static void
-sysprof_notebook_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofNotebook *self = (SysprofNotebook *)object;
-
- switch (prop_id)
- {
- case PROP_ALWAYS_SHOW_TABS:
- g_value_set_boolean (value, sysprof_notebook_get_always_show_tabs (self));
- break;
-
- case PROP_CAN_REPLAY:
- g_value_set_boolean (value, sysprof_notebook_get_can_replay (self));
- break;
-
- case PROP_CAN_SAVE:
- g_value_set_boolean (value, sysprof_notebook_get_can_save (self));
- break;
-
- case PROP_CURRENT:
- g_value_set_object (value, sysprof_notebook_get_current (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_notebook_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofNotebook *self = (SysprofNotebook *)object;
-
- switch (prop_id)
- {
- case PROP_ALWAYS_SHOW_TABS:
- sysprof_notebook_set_always_show_tabs (self, g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_notebook_class_init (SysprofNotebookClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = sysprof_notebook_dispose;
- object_class->get_property = sysprof_notebook_get_property;
- object_class->set_property = sysprof_notebook_set_property;
-
- properties [PROP_ALWAYS_SHOW_TABS] =
- g_param_spec_boolean ("always-show-tabs",
- "Always Show Tabs",
- "Always Show Tabs",
- FALSE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CAN_REPLAY] =
- g_param_spec_boolean ("can-replay",
- "Can Replay",
- "If the current display can replay a recording",
- FALSE,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CAN_SAVE] =
- g_param_spec_boolean ("can-save",
- "Can Save",
- "If the current display can save a recording",
- FALSE,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CURRENT] =
- g_param_spec_object ("current",
- "Current",
- "The current display",
- SYSPROF_TYPE_DISPLAY,
- (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
-}
-
-static void
-sysprof_notebook_init (SysprofNotebook *self)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- priv->notebook = GTK_NOTEBOOK (gtk_notebook_new ());
- gtk_widget_set_parent (GTK_WIDGET (priv->notebook), GTK_WIDGET (self));
-
- gtk_notebook_set_show_border (priv->notebook, FALSE);
- gtk_notebook_set_scrollable (priv->notebook, TRUE);
- gtk_notebook_popup_enable (priv->notebook);
-
- g_signal_connect_object (priv->notebook,
- "page-added",
- G_CALLBACK (sysprof_notebook_page_added),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->notebook,
- "page-removed",
- G_CALLBACK (sysprof_notebook_page_removed),
- self,
- G_CONNECT_SWAPPED);
-
- g_signal_connect_object (priv->notebook,
- "switch-page",
- G_CALLBACK (sysprof_notebook_switch_page),
- self,
- G_CONNECT_SWAPPED | G_CONNECT_AFTER);
-}
-
-void
-sysprof_notebook_close_current (SysprofNotebook *self)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
- gint page;
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
-
- if ((page = gtk_notebook_get_current_page (priv->notebook)) >= 0)
- gtk_notebook_remove_page (priv->notebook, page);
-}
-
-void
-sysprof_notebook_open (SysprofNotebook *self,
- GFile *file)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
- SysprofDisplay *display = NULL;
- int page;
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
- g_return_if_fail (g_file_is_native (file));
-
- for (page = 0; page < sysprof_notebook_get_n_pages (self); page++)
- {
- SysprofDisplay *child = sysprof_notebook_get_nth_page (self, page);
-
- if (sysprof_display_is_empty (child))
- {
- display = child;
- break;
- }
- }
-
- if (display == NULL)
- {
- display = SYSPROF_DISPLAY (sysprof_display_new ());
- page = sysprof_notebook_append (self, display);
- }
- else
- {
- page = gtk_notebook_page_num (priv->notebook, GTK_WIDGET (display));
- }
-
- sysprof_notebook_set_current_page (self, page);
-
- sysprof_display_open (SYSPROF_DISPLAY (display), file);
-}
-
-SysprofDisplay *
-sysprof_notebook_get_current (SysprofNotebook *self)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
- gint page;
-
- g_assert (SYSPROF_IS_NOTEBOOK (self));
-
- if ((page = gtk_notebook_get_current_page (priv->notebook)) >= 0)
- return SYSPROF_DISPLAY (gtk_notebook_get_nth_page (priv->notebook, page));
-
- return NULL;
-}
-
-void
-sysprof_notebook_save (SysprofNotebook *self)
-{
- SysprofDisplay *display;
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
-
- if ((display = sysprof_notebook_get_current (self)))
- sysprof_display_save (display);
-}
-
-gboolean
-sysprof_notebook_get_can_save (SysprofNotebook *self)
-{
- SysprofDisplay *display;
-
- g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), FALSE);
-
- if ((display = sysprof_notebook_get_current (self)))
- return sysprof_display_get_can_save (display);
-
- return FALSE;
-}
-
-gboolean
-sysprof_notebook_get_can_replay (SysprofNotebook *self)
-{
- SysprofDisplay *display;
-
- g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), FALSE);
-
- if ((display = sysprof_notebook_get_current (self)))
- return sysprof_display_get_can_replay (display);
-
- return FALSE;
-}
-
-void
-sysprof_notebook_replay (SysprofNotebook *self)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
- SysprofDisplay *display;
- SysprofDisplay *replay;
- gint page;
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
-
- if (!(display = sysprof_notebook_get_current (self)) ||
- !sysprof_display_get_can_replay (display) ||
- !(replay = sysprof_display_replay (display)))
- return;
-
- g_return_if_fail (SYSPROF_IS_DISPLAY (replay));
-
- gtk_widget_show (GTK_WIDGET (replay));
- gtk_notebook_append_page (priv->notebook, GTK_WIDGET (replay), NULL);
- page = gtk_notebook_page_num (priv->notebook, GTK_WIDGET (replay));
- gtk_notebook_set_current_page (priv->notebook, page);
-}
-
-void
-sysprof_notebook_add_profiler (SysprofNotebook *self,
- SysprofProfiler *profiler)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
- GtkWidget *display;
- gint page;
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
- g_return_if_fail (SYSPROF_IS_PROFILER (profiler));
-
- display = sysprof_display_new_for_profiler (profiler);
-
- gtk_widget_show (display);
- gtk_notebook_append_page (priv->notebook, GTK_WIDGET (display), NULL);
- page = gtk_notebook_page_num (priv->notebook, display);
- gtk_notebook_set_current_page (priv->notebook, page);
-}
-
-gboolean
-sysprof_notebook_get_always_show_tabs (SysprofNotebook *self)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), FALSE);
-
- return priv->always_show_tabs;
-}
-
-void
-sysprof_notebook_set_always_show_tabs (SysprofNotebook *self,
- gboolean always_show_tabs)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
-
- always_show_tabs = !!always_show_tabs;
-
- if (always_show_tabs != priv->always_show_tabs)
- {
- priv->always_show_tabs = always_show_tabs;
- gtk_notebook_set_show_tabs (priv->notebook,
- (priv->always_show_tabs ||
- gtk_notebook_get_n_pages (priv->notebook) > 1));
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ALWAYS_SHOW_TABS]);
- }
-}
-
-static void
-sysprof_notebook_add_child (GtkBuildable *buildable,
- GtkBuilder *builder,
- GObject *child,
- const char *type)
-{
- SysprofNotebook *self = (SysprofNotebook *)buildable;
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_assert (SYSPROF_IS_NOTEBOOK (self));
-
- if (SYSPROF_IS_DISPLAY (child))
- gtk_notebook_append_page (priv->notebook, GTK_WIDGET (child), NULL);
- else
- g_warning ("Cannot add child of type %s to %s",
- G_OBJECT_TYPE_NAME (child),
- G_OBJECT_TYPE_NAME (self));
-}
-
-static void
-buildable_iface_init (GtkBuildableIface *iface)
-{
- iface->add_child = sysprof_notebook_add_child;
-}
-
-guint
-sysprof_notebook_get_n_pages (SysprofNotebook *self)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), 0);
-
- return gtk_notebook_get_n_pages (priv->notebook);
-}
-
-SysprofDisplay *
-sysprof_notebook_get_nth_page (SysprofNotebook *self,
- guint nth)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), NULL);
-
- return SYSPROF_DISPLAY (gtk_notebook_get_nth_page (priv->notebook, nth));
-}
-
-void
-sysprof_notebook_set_current_page (SysprofNotebook *self,
- int nth)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_NOTEBOOK (self));
-
- gtk_notebook_set_current_page (priv->notebook, nth);
-}
-
-int
-sysprof_notebook_append (SysprofNotebook *self,
- SysprofDisplay *display)
-{
- SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_NOTEBOOK (self), -1);
- g_return_val_if_fail (SYSPROF_IS_DISPLAY (display), -1);
-
- return gtk_notebook_append_page (priv->notebook, GTK_WIDGET (display), NULL);
-}
diff --git a/src/libsysprof-ui/sysprof-notebook.h b/src/libsysprof-ui/sysprof-notebook.h
deleted file mode 100644
index 943dc1f1..00000000
--- a/src/libsysprof-ui/sysprof-notebook.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* sysprof-notebook.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
-# error "Only can be included directly."
-#endif
-
-#include
-#include
-
-#include "sysprof-display.h"
-#include "sysprof-version-macros.h"
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_NOTEBOOK (sysprof_notebook_get_type())
-
-SYSPROF_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE (SysprofNotebook, sysprof_notebook, SYSPROF, NOTEBOOK, GtkWidget)
-
-struct _SysprofNotebookClass
-{
- GtkWidgetClass parent_class;
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-SYSPROF_AVAILABLE_IN_ALL
-GtkWidget *sysprof_notebook_new (void);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofDisplay *sysprof_notebook_get_current (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_close_current (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_open (SysprofNotebook *self,
- GFile *file);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_save (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_notebook_get_can_save (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_replay (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_notebook_get_can_replay (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_add_profiler (SysprofNotebook *self,
- SysprofProfiler *profiler);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_notebook_get_always_show_tabs (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_set_always_show_tabs (SysprofNotebook *self,
- gboolean always_show_tabs);
-SYSPROF_AVAILABLE_IN_ALL
-guint sysprof_notebook_get_n_pages (SysprofNotebook *self);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofDisplay *sysprof_notebook_get_nth_page (SysprofNotebook *self,
- guint nth);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_notebook_set_current_page (SysprofNotebook *self,
- int page);
-SYSPROF_AVAILABLE_IN_ALL
-int sysprof_notebook_append (SysprofNotebook *self,
- SysprofDisplay *display);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-page.c b/src/libsysprof-ui/sysprof-page.c
deleted file mode 100644
index 45f61152..00000000
--- a/src/libsysprof-ui/sysprof-page.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* sysprof-page.c
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-page"
-
-#include "config.h"
-
-#include "sysprof-display.h"
-#include "sysprof-page.h"
-#include "sysprof-ui-private.h"
-
-typedef struct
-{
- gchar *title;
-} SysprofPagePrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofPage, sysprof_page, GTK_TYPE_WIDGET)
-
-enum {
- PROP_0,
- PROP_TITLE,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-/**
- * sysprof_page_new:
- *
- * Create a new #SysprofPage.
- *
- * Returns: (transfer full) (type SysprofPage): a newly created #SysprofPage
- */
-GtkWidget *
-sysprof_page_new (void)
-{
- return g_object_new (SYSPROF_TYPE_PAGE, NULL);
-}
-
-const gchar *
-sysprof_page_get_title (SysprofPage *self)
-{
- SysprofPagePrivate *priv = sysprof_page_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_PAGE (self), NULL);
-
- return priv->title;
-}
-
-void
-sysprof_page_set_title (SysprofPage *self,
- const gchar *title)
-{
- SysprofPagePrivate *priv = sysprof_page_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_PAGE (self));
-
- if (g_strcmp0 (priv->title, title) != 0)
- {
- g_free (priv->title);
- priv->title = g_strdup (title);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
- }
-}
-
-static void
-sysprof_page_real_load_async (SysprofPage *self,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *condition,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_task_report_new_error (self, callback, user_data,
- sysprof_page_load_async,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "Operation not supported");
-}
-
-static gboolean
-sysprof_page_real_load_finish (SysprofPage *self,
- GAsyncResult *result,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-sysprof_page_dispose (GObject *object)
-{
- SysprofPage *self = (SysprofPage *)object;
- SysprofPagePrivate *priv = sysprof_page_get_instance_private (self);
- GtkWidget *child;
-
- g_clear_pointer (&priv->title, g_free);
-
- while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
- gtk_widget_unparent (child);
-
- G_OBJECT_CLASS (sysprof_page_parent_class)->dispose (object);
-}
-
-static void
-sysprof_page_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofPage *self = SYSPROF_PAGE (object);
-
- switch (prop_id)
- {
- case PROP_TITLE:
- g_value_set_string (value, sysprof_page_get_title (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_page_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofPage *self = SYSPROF_PAGE (object);
-
- switch (prop_id)
- {
- case PROP_TITLE:
- sysprof_page_set_title (self, g_value_get_string (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_page_class_init (SysprofPageClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->dispose = sysprof_page_dispose;
- object_class->get_property = sysprof_page_get_property;
- object_class->set_property = sysprof_page_set_property;
-
- klass->load_async = sysprof_page_real_load_async;
- klass->load_finish = sysprof_page_real_load_finish;
-
- properties [PROP_TITLE] =
- g_param_spec_string ("title",
- "Title",
- "The title for the page",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
-}
-
-static void
-sysprof_page_init (SysprofPage *self)
-{
- gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
-}
-
-/**
- * sysprof_page_load_async:
- * @condition: (nullable): a #sysprofCaptureCondition or %NULL
- * @cancellable: (nullable): a #GCancellable or %NULL
- *
- * Since: 3.34
- */
-void
-sysprof_page_load_async (SysprofPage *self,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *condition,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_return_if_fail (SYSPROF_IS_PAGE (self));
- g_return_if_fail (reader != NULL);
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- SYSPROF_PAGE_GET_CLASS (self)->load_async (self, reader, selection, condition, cancellable, callback, user_data);
-}
-
-gboolean
-sysprof_page_load_finish (SysprofPage *self,
- GAsyncResult *result,
- GError **error)
-{
- g_return_val_if_fail (SYSPROF_IS_PAGE (self), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
-
- return SYSPROF_PAGE_GET_CLASS (self)->load_finish (self, result, error);
-}
-
-void
-sysprof_page_set_size_group (SysprofPage *self,
- GtkSizeGroup *size_group)
-{
- g_return_if_fail (SYSPROF_IS_PAGE (self));
- g_return_if_fail (!size_group || GTK_IS_SIZE_GROUP (size_group));
-
- if (SYSPROF_PAGE_GET_CLASS (self)->set_size_group)
- SYSPROF_PAGE_GET_CLASS (self)->set_size_group (self, size_group);
-}
-
-void
-sysprof_page_set_hadjustment (SysprofPage *self,
- GtkAdjustment *hadjustment)
-{
- g_return_if_fail (SYSPROF_IS_PAGE (self));
- g_return_if_fail (!hadjustment || GTK_IS_ADJUSTMENT (hadjustment));
-
- if (SYSPROF_PAGE_GET_CLASS (self)->set_hadjustment)
- SYSPROF_PAGE_GET_CLASS (self)->set_hadjustment (self, hadjustment);
-}
-
-void
-sysprof_page_reload (SysprofPage *self)
-{
- GtkWidget *display;
-
- g_return_if_fail (SYSPROF_IS_PAGE (self));
-
- if ((display = gtk_widget_get_ancestor (GTK_WIDGET (self), SYSPROF_TYPE_DISPLAY)))
- _sysprof_display_reload_page (SYSPROF_DISPLAY (display), self);
-}
diff --git a/src/libsysprof-ui/sysprof-page.h b/src/libsysprof-ui/sysprof-page.h
deleted file mode 100644
index 22d55044..00000000
--- a/src/libsysprof-ui/sysprof-page.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* sysprof-page.h
- *
- * Copyright 2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
-# error "Only can be included directly."
-#endif
-
-#include
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_PAGE (sysprof_page_get_type())
-
-SYSPROF_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE (SysprofPage, sysprof_page, SYSPROF, PAGE, GtkWidget)
-
-struct _SysprofPageClass
-{
- GtkWidgetClass parent_class;
-
- void (*load_async) (SysprofPage *self,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *condition,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
- gboolean (*load_finish) (SysprofPage *self,
- GAsyncResult *result,
- GError **error);
- void (*set_hadjustment) (SysprofPage *self,
- GtkAdjustment *hadjustment);
- void (*set_size_group) (SysprofPage *self,
- GtkSizeGroup *size_group);
-
- /*< private >*/
- gpointer _reserved[16];
-};
-
-SYSPROF_AVAILABLE_IN_ALL
-GtkWidget *sysprof_page_new (void);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_page_load_async (SysprofPage *self,
- SysprofCaptureReader *reader,
- SysprofSelection *selection,
- SysprofCaptureCondition *condition,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_page_load_finish (SysprofPage *self,
- GAsyncResult *result,
- GError **error);
-SYSPROF_AVAILABLE_IN_3_36
-void sysprof_page_reload (SysprofPage *self);
-SYSPROF_AVAILABLE_IN_ALL
-const gchar *sysprof_page_get_title (SysprofPage *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_page_set_title (SysprofPage *self,
- const gchar *title);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_page_set_hadjustment (SysprofPage *self,
- GtkAdjustment *hadjustment);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_page_set_size_group (SysprofPage *self,
- GtkSizeGroup *size_group);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-process-model-row.c b/src/libsysprof-ui/sysprof-process-model-row.c
deleted file mode 100644
index aa046f39..00000000
--- a/src/libsysprof-ui/sysprof-process-model-row.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* sysprof-process-model-row.c
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#define G_LOG_DOMAIN "sysprof-process-model-row"
-
-#include "config.h"
-
-#include "sysprof-process-model-row.h"
-
-typedef struct
-{
- SysprofProcessModelItem *item;
-
- GtkLabel *args_label;
- GtkLabel *label;
- GtkLabel *pid;
- GtkImage *image;
- GtkImage *check;
-} SysprofProcessModelRowPrivate;
-
-G_DEFINE_TYPE_WITH_PRIVATE (SysprofProcessModelRow, sysprof_process_model_row, GTK_TYPE_LIST_BOX_ROW)
-
-enum {
- PROP_0,
- PROP_ITEM,
- PROP_SELECTED,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-GtkWidget *
-sysprof_process_model_row_new (SysprofProcessModelItem *item)
-{
- return g_object_new (SYSPROF_TYPE_PROCESS_MODEL_ROW,
- "item", item,
- NULL);
-}
-
-SysprofProcessModelItem *
-sysprof_process_model_row_get_item (SysprofProcessModelRow *self)
-{
- SysprofProcessModelRowPrivate *priv = sysprof_process_model_row_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_PROCESS_MODEL_ROW (self), NULL);
-
- return priv->item;
-}
-
-static void
-sysprof_process_model_row_set_item (SysprofProcessModelRow *self,
- SysprofProcessModelItem *item)
-{
- SysprofProcessModelRowPrivate *priv = sysprof_process_model_row_get_instance_private (self);
-
- g_assert (SYSPROF_IS_PROCESS_MODEL_ROW (self));
- g_assert (SYSPROF_IS_PROCESS_MODEL_ITEM (item));
-
- if (g_set_object (&priv->item, item))
- {
- const gchar *command_line;
- g_auto(GStrv) parts = NULL;
- g_autofree gchar *pidstr = NULL;
- const gchar * const *argv;
- GPid pid;
-
- command_line = sysprof_process_model_item_get_command_line (item);
- parts = g_strsplit (command_line ?: "", "\n", 0);
- gtk_label_set_label (priv->label, parts [0]);
-
- if ((NULL != (argv = sysprof_process_model_item_get_argv (item))) && (argv[0] != NULL))
- {
- g_autofree gchar *argvstr = g_strjoinv (" ", (gchar **)&argv[1]);
- g_autofree gchar *escaped = g_markup_escape_text (argvstr, -1);
-
- gtk_label_set_label (priv->args_label, escaped);
- }
-
- pid = sysprof_process_model_item_get_pid (item);
- pidstr = g_strdup_printf ("%u", pid);
- gtk_label_set_label (priv->pid, pidstr);
- gtk_label_set_use_markup (priv->pid, TRUE);
- }
-}
-
-gboolean
-sysprof_process_model_row_get_selected (SysprofProcessModelRow *self)
-{
- SysprofProcessModelRowPrivate *priv = sysprof_process_model_row_get_instance_private (self);
-
- g_return_val_if_fail (SYSPROF_IS_PROCESS_MODEL_ROW (self), FALSE);
-
- return gtk_widget_get_visible (GTK_WIDGET (priv->check));
-}
-
-void
-sysprof_process_model_row_set_selected (SysprofProcessModelRow *self,
- gboolean selected)
-{
- SysprofProcessModelRowPrivate *priv = sysprof_process_model_row_get_instance_private (self);
-
- g_return_if_fail (SYSPROF_IS_PROCESS_MODEL_ROW (self));
-
- selected = !!selected;
-
- if (selected != sysprof_process_model_row_get_selected (self))
- {
- gtk_widget_set_visible (GTK_WIDGET (priv->check), selected);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTED]);
- }
-}
-
-static gboolean
-sysprof_process_model_row_query_tooltip (GtkWidget *widget,
- gint x,
- gint y,
- gboolean keyboard_mode,
- GtkTooltip *tooltip)
-{
- SysprofProcessModelRow *self = (SysprofProcessModelRow *)widget;
- SysprofProcessModelRowPrivate *priv = sysprof_process_model_row_get_instance_private (self);
-
- g_assert (SYSPROF_IS_PROCESS_MODEL_ROW (self));
- g_assert (GTK_IS_TOOLTIP (tooltip));
-
- if (priv->item != NULL)
- {
- const gchar * const *argv = sysprof_process_model_item_get_argv (priv->item);
-
- if (argv != NULL)
- {
- g_autofree gchar *str = g_strjoinv (" ", (gchar **)argv);
- gtk_tooltip_set_text (tooltip, str);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static void
-sysprof_process_model_row_finalize (GObject *object)
-{
- SysprofProcessModelRow *self = (SysprofProcessModelRow *)object;
- SysprofProcessModelRowPrivate *priv = sysprof_process_model_row_get_instance_private (self);
-
- g_clear_object (&priv->item);
-
- G_OBJECT_CLASS (sysprof_process_model_row_parent_class)->finalize (object);
-}
-
-static void
-sysprof_process_model_row_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- SysprofProcessModelRow *self = SYSPROF_PROCESS_MODEL_ROW (object);
-
- switch (prop_id)
- {
- case PROP_ITEM:
- g_value_set_object (value, sysprof_process_model_row_get_item (self));
- break;
-
- case PROP_SELECTED:
- g_value_set_boolean (value, sysprof_process_model_row_get_selected (self));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_process_model_row_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- SysprofProcessModelRow *self = SYSPROF_PROCESS_MODEL_ROW (object);
-
- switch (prop_id)
- {
- case PROP_ITEM:
- sysprof_process_model_row_set_item (self, g_value_get_object (value));
- break;
-
- case PROP_SELECTED:
- sysprof_process_model_row_set_selected (self, g_value_get_boolean (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-sysprof_process_model_row_class_init (SysprofProcessModelRowClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->finalize = sysprof_process_model_row_finalize;
- object_class->get_property = sysprof_process_model_row_get_property;
- object_class->set_property = sysprof_process_model_row_set_property;
-
- widget_class->query_tooltip = sysprof_process_model_row_query_tooltip;
-
- properties [PROP_ITEM] =
- g_param_spec_object ("item",
- "Item",
- "Item",
- SYSPROF_TYPE_PROCESS_MODEL_ITEM,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_SELECTED] =
- g_param_spec_boolean ("selected",
- "Selected",
- "Selected",
- FALSE,
- (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-
- gtk_widget_class_set_template_from_resource (widget_class,
- "/org/gnome/sysprof/ui/sysprof-process-model-row.ui");
- gtk_widget_class_bind_template_child_private (widget_class, SysprofProcessModelRow, args_label);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofProcessModelRow, image);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofProcessModelRow, label);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofProcessModelRow, pid);
- gtk_widget_class_bind_template_child_private (widget_class, SysprofProcessModelRow, check);
-}
-
-static void
-sysprof_process_model_row_init (SysprofProcessModelRow *self)
-{
- gtk_widget_init_template (GTK_WIDGET (self));
-
- gtk_widget_set_has_tooltip (GTK_WIDGET (self), TRUE);
-}
diff --git a/src/libsysprof-ui/sysprof-process-model-row.h b/src/libsysprof-ui/sysprof-process-model-row.h
deleted file mode 100644
index 63100357..00000000
--- a/src/libsysprof-ui/sysprof-process-model-row.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* sysprof-process-model-row.h
- *
- * Copyright 2016-2019 Christian Hergert
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
-# error "Only can be included directly."
-#endif
-
-#include
-#include
-
-G_BEGIN_DECLS
-
-#define SYSPROF_TYPE_PROCESS_MODEL_ROW (sysprof_process_model_row_get_type())
-
-SYSPROF_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE (SysprofProcessModelRow, sysprof_process_model_row, SYSPROF, PROCESS_MODEL_ROW, GtkListBoxRow)
-
-struct _SysprofProcessModelRowClass
-{
- GtkListBoxRowClass parent;
-
- gpointer padding[4];
-};
-
-SYSPROF_AVAILABLE_IN_ALL
-GtkWidget *sysprof_process_model_row_new (SysprofProcessModelItem *item);
-SYSPROF_AVAILABLE_IN_ALL
-SysprofProcessModelItem *sysprof_process_model_row_get_item (SysprofProcessModelRow *self);
-SYSPROF_AVAILABLE_IN_ALL
-gboolean sysprof_process_model_row_get_selected (SysprofProcessModelRow *self);
-SYSPROF_AVAILABLE_IN_ALL
-void sysprof_process_model_row_set_selected (SysprofProcessModelRow *self,
- gboolean selected);
-
-G_END_DECLS
diff --git a/src/libsysprof-ui/sysprof-process-model-row.ui b/src/libsysprof-ui/sysprof-process-model-row.ui
deleted file mode 100644
index ee23e296..00000000
--- a/src/libsysprof-ui/sysprof-process-model-row.ui
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-