summaryrefslogtreecommitdiffstats
path: root/Vector.c
diff options
context:
space:
mode:
authorCharlie Vieth <charlie.vieth@gmail.com>2022-02-05 18:47:43 -0500
committerBenBE <BenBE@geshi.org>2022-05-05 09:17:51 +0200
commit08166b27b191e7be62d74054d92a9720c3a141ab (patch)
treec5b839805f0565b11058ff7b7832b5fadfb4bc55 /Vector.c
parentc7413fd6771b65388bea14ef42863444c6eaa419 (diff)
ProcessList: fix quadratic process removal when scanning
This commit changes ProcessList_scan to lazily remove Processes by index, which is known, instead of performing a brute-force search by pid and immediately reclaiming the lost vector space via compaction. Searching by pid is potentially quadratic in ProcessList_scan because the process we are searching for is always at the back of the vector (the scan starts from the back of the vector). Additionally, removal via Vector_remove immediately reclaims space (by sliding elements down). With these changes process removal in ProcessList_scan is now linear. Changes: * ProcessList: add new ProcessList_removeIndex function to remove by index * Vector: add Vector_softRemove and Vector_compact functions to support lazy removal/deletion of entries Vector_softRemove Vector_compact * Vector: replace Vector_count with Vector_countEquals since it only used for consistency assertions.
Diffstat (limited to 'Vector.c')
-rw-r--r--Vector.c81
1 files changed, 74 insertions, 7 deletions
diff --git a/Vector.c b/Vector.c
index 52ed44a7..04881503 100644
--- a/Vector.c
+++ b/Vector.c
@@ -29,6 +29,8 @@ Vector* Vector_new(const ObjectClass* type, bool owner, int size) {
this->items = 0;
this->type = type;
this->owner = owner;
+ this->dirty_index = -1;
+ this->dirty_count = 0;
return this;
}
@@ -44,10 +46,21 @@ void Vector_delete(Vector* this) {
free(this);
}
+static inline bool Vector_isDirty(const Vector* this) {
+ if (this->dirty_count > 0) {
+ assert(0 <= this->dirty_index && this->dirty_index < this->items);
+ assert(this->dirty_count <= this->items);
+ return true;
+ }
+ assert(this->dirty_index == -1);
+ return false;
+}
+
#ifndef NDEBUG
static bool Vector_isConsistent(const Vector* this) {
assert(this->items <= this->arraySize);
+ assert(!Vector_isDirty(this));
if (this->owner) {
for (int i = 0; i < this->items; i++) {
@@ -60,15 +73,14 @@ static bool Vector_isConsistent(const Vector* this) {
return true;
}
-unsigned int Vector_count(const Vector* this) {
- unsigned int items = 0;
+bool Vector_countEquals(const Vector* this, unsigned int expectedCount) {
+ unsigned int n = 0;
for (int i = 0; i < this->items; i++) {
if (this->array[i]) {
- items++;
+ n++;
}
}
- assert(items == (unsigned int)this->items);
- return items;
+ return n == expectedCount;
}
Object* Vector_get(const Vector* this, int idx) {
@@ -88,13 +100,16 @@ int Vector_size(const Vector* this) {
void Vector_prune(Vector* this) {
assert(Vector_isConsistent(this));
if (this->owner) {
- for (int i = 0; i < this->items; i++)
+ for (int i = 0; i < this->items; i++) {
if (this->array[i]) {
Object_delete(this->array[i]);
- //this->array[i] = NULL;
+ this->array[i] = NULL;
}
+ }
}
this->items = 0;
+ this->dirty_index = -1;
+ this->dirty_count = 0;
}
//static int comparisons = 0;
@@ -242,6 +257,58 @@ Object* Vector_remove(Vector* this, int idx) {
}
}
+Object* Vector_softRemove(Vector* this, int idx) {
+ assert(idx >= 0 && idx < this->items);
+
+ Object* removed = this->array[idx];
+ assert(removed);
+ if (removed) {
+ this->array[idx] = NULL;
+
+ this->dirty_count++;
+ if (this->dirty_index < 0 || idx < this->dirty_index) {
+ this->dirty_index = idx;
+ }
+
+ if (this->owner) {
+ Object_delete(removed);
+ return NULL;
+ }
+ }
+
+ return removed;
+}
+
+void Vector_compact(Vector* this) {
+ if (!Vector_isDirty(this)) {
+ return;
+ }
+
+ const int size = this->items;
+ assert(0 <= this->dirty_index && this->dirty_index < size);
+ assert(this->array[this->dirty_index] == NULL);
+
+ int idx = this->dirty_index;
+
+ /* one deletion: use memmove, which should be faster */
+ if (this->dirty_count == 1) {
+ memmove(&this->array[idx], &this->array[idx + 1], (this->items - idx) * sizeof(this->array[0]));
+ } else {
+ /* multiple deletions */
+ for (int i = idx + 1; i < size; i++) {
+ if (this->array[i]) {
+ this->array[idx++] = this->array[i];
+ }
+ }
+ }
+
+ this->items -= this->dirty_count;
+ this->dirty_index = -1;
+ this->dirty_count = 0;
+
+ assert(Vector_isConsistent(this));
+}
+
void Vector_moveUp(Vector* this, int idx) {
assert(idx >= 0 && idx < this->items);
assert(Vector_isConsistent(this));

© 2014-2024 Faster IT GmbH | imprint | privacy policy