# #
#############################################################################*/
+#include <errno.h>
#include <stdlib.h>
-#include <sys/queue.h>
#include <solv/queue.h>
#include <pakfire/packagelist.h>
#include <pakfire/pakfire.h>
-struct pakfire_packagelist_element {
- TAILQ_ENTRY(pakfire_packagelist_element) nodes;
-
- struct pakfire_package* pkg;
-};
-
struct pakfire_packagelist {
struct pakfire_ctx* ctx;
int nrefs;
- TAILQ_HEAD(entries, pakfire_packagelist_element) packages;
+ struct pakfire_package** packages;
+ unsigned int num_packages;
};
-static void pakfire_packagelist_clear(struct pakfire_packagelist* list) {
- struct pakfire_packagelist_element* element = NULL;
-
- while (!TAILQ_EMPTY(&list->packages)) {
- // Fetch the first element
- element = TAILQ_FIRST(&list->packages);
-
- // Remove it from the list
- TAILQ_REMOVE(&list->packages, element, nodes);
+static void pakfire_packagelist_clear(struct pakfire_packagelist* self) {
+ if (self->packages) {
+ for (unsigned int i = 0; i < self->num_packages; i++)
+ pakfire_package_unref(self->packages[i]);
- // Dereference the file
- pakfire_package_unref(element->pkg);
+ // Free the array
+ free(self->packages);
+ self->packages = NULL;
- // Free it all
- free(element);
+ // Reset number of files on the list
+ self->num_packages = 0;
}
}
static void pakfire_packagelist_free(struct pakfire_packagelist* list) {
pakfire_packagelist_clear(list);
+
if (list->ctx)
pakfire_ctx_unref(list->ctx);
free(list);
}
-int pakfire_packagelist_create(
- struct pakfire_packagelist** list, struct pakfire_ctx* ctx) {
- struct pakfire_packagelist* l = calloc(1, sizeof(*l));
- if (!l)
- return 1;
+int pakfire_packagelist_create(struct pakfire_packagelist** list, struct pakfire_ctx* ctx) {
+ struct pakfire_packagelist* self = NULL;
+
+ // Allocate some memory
+ self = calloc(1, sizeof(*self));
+ if (!self)
+ return -errno;
// Store a reference to the context
- l->ctx = pakfire_ctx_ref(ctx);
+ self->ctx = pakfire_ctx_ref(ctx);
// Initialize the reference counter
- l->nrefs = 1;
+ self->nrefs = 1;
- // Initialise packages
- TAILQ_INIT(&l->packages);
+ // Return the pointer
+ *list = self;
- *list = l;
return 0;
}
-struct pakfire_packagelist* pakfire_packagelist_ref(struct pakfire_packagelist* list) {
- list->nrefs++;
+struct pakfire_packagelist* pakfire_packagelist_ref(struct pakfire_packagelist* self) {
+ self->nrefs++;
- return list;
+ return self;
}
-struct pakfire_packagelist* pakfire_packagelist_unref(struct pakfire_packagelist* list) {
- if (--list->nrefs > 0)
- return list;
+struct pakfire_packagelist* pakfire_packagelist_unref(struct pakfire_packagelist* self) {
+ if (--self->nrefs > 0)
+ return self;
- pakfire_packagelist_free(list);
+ pakfire_packagelist_free(self);
return NULL;
}
-size_t pakfire_packagelist_length(struct pakfire_packagelist* list) {
- struct pakfire_packagelist_element* element = NULL;
- size_t size = 0;
+size_t pakfire_packagelist_length(struct pakfire_packagelist* self) {
+ return self->num_packages;
+}
- TAILQ_FOREACH(element, &list->packages, nodes)
- size++;
+struct pakfire_package* pakfire_packagelist_get(struct pakfire_packagelist* self, unsigned int index) {
+ // Check that index is in range
+ if (index >= self->num_packages) {
+ errno = ERANGE;
+ return NULL;
+ }
- return size;
+ return pakfire_package_ref(self->packages[index]);
}
-struct pakfire_package* pakfire_packagelist_get(struct pakfire_packagelist* list, unsigned int index) {
- struct pakfire_packagelist_element* element = NULL;
+static int pakfire_packagelist_search(struct pakfire_packagelist* self, struct pakfire_package* pkg) {
+ int i;
+ int r;
- // Fetch the first element
- element = TAILQ_FIRST(&list->packages);
+ // Set starting points
+ int lo = 0;
+ int hi = self->num_packages;
- while (element && index--)
- element = TAILQ_NEXT(element, nodes);
+ while (lo < hi) {
+ // Find the middle
+ i = (lo + hi) / 2;
- if (!element)
- return NULL;
-
- return pakfire_package_ref(element->pkg);
-}
+ // Compare the packages
+ r = pakfire_package_cmp(self->packages[i], pkg);
-int pakfire_packagelist_push(struct pakfire_packagelist* list, struct pakfire_package* pkg) {
- struct pakfire_packagelist_element* element = NULL;
- struct pakfire_packagelist_element* e = NULL;
+ // If the file is greater than the middle, we only need to search in the left half
+ if (r >= 0)
+ hi = i;
- // Allocate a new element
- element = calloc(1, sizeof *element);
- if (!element) {
- ERROR(list->ctx, "Could not allocate a new packagelist element: %m\n");
- return 1;
+ // Otherwise we need to search in the right half
+ else
+ lo = i + 1;
}
- // Reference the package
- element->pkg = pakfire_package_ref(pkg);
-
- // Fetch the last element
- e = TAILQ_LAST(&list->packages, entries);
+ return lo;
+}
- // Skip all elements that are "greater than" the element we want to add
- while (e) {
- if (pakfire_package_cmp(e->pkg, pkg) <= 0)
- break;
+int pakfire_packagelist_push(struct pakfire_packagelist* self, struct pakfire_package* pkg) {
+ // Find the index where the package should go
+ int pos = pakfire_packagelist_search(self, pkg);
- e = TAILQ_PREV(e, entries, nodes);
+ // Make space
+ self->packages = reallocarray(self->packages, self->num_packages + 1, sizeof(*self->packages));
+ if (!self->packages) {
+ ERROR(self->ctx, "Could not allocate packagelist: %m\n");
+ return -errno;
}
- // If we found an element on the list, we will append after it,
- // otherwise we add right at the start.
- if (e)
- TAILQ_INSERT_AFTER(&list->packages, e, element, nodes);
- else
- TAILQ_INSERT_HEAD(&list->packages, element, nodes);
+ // Move everything up one slot
+ for (int i = self->num_packages; i > pos; i--)
+ self->packages[i] = self->packages[i - 1];
+
+ // Store the package
+ self->packages[pos] = pakfire_package_ref(pkg);
+
+ // The list is now longer
+ ++self->num_packages;
return 0;
}
-int pakfire_packagelist_walk(struct pakfire_packagelist* list,
+int pakfire_packagelist_walk(struct pakfire_packagelist* self,
pakfire_packagelist_walk_callback callback, void* data, int flags) {
- struct pakfire_packagelist_element* element = NULL;
int kept_going = 0;
int r = 0;
// Call the callback once for every element on the list
- TAILQ_FOREACH(element, &list->packages, nodes) {
+ for (unsigned int i = 0; i < self->num_packages; i++) {
// Call the callback
- r = callback(list->ctx, element->pkg, data);
+ r = callback(self->ctx, self->packages[i], data);
// Continue if there was no error
if (r == 0)
return (kept_going > 0) ? kept_going : r;
}
-int pakfire_packagelist_import_solvables(struct pakfire_packagelist* list,
+int pakfire_packagelist_import_solvables(struct pakfire_packagelist* self,
struct pakfire* pakfire, Queue* q) {
struct pakfire_package* pkg = NULL;
int r;
if (r)
return r;
- r = pakfire_packagelist_push(list, pkg);
+ r = pakfire_packagelist_push(self, pkg);
pakfire_package_unref(pkg);
if (r)
return r;