From 71cd7af17b450b699a9cc42827fbd7a6347d3573 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Mon, 7 Sep 2020 16:59:21 -0700 Subject: [PATCH] [kutil] Add sorted insert to kutil::vector Added a sorted insert to vector, as well as cleaning up and extending the removal functions. --- modules.yaml | 1 + src/libraries/kutil/include/kutil/vector.h | 66 ++++++++++++++++++++-- src/tests/container_helpers.h | 13 +++++ src/tests/linked_list.cpp | 12 +--- src/tests/vector.cpp | 25 ++++++++ 5 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 src/tests/container_helpers.h create mode 100644 src/tests/vector.cpp diff --git a/modules.yaml b/modules.yaml index caa08dd..74b2bb0 100644 --- a/modules.yaml +++ b/modules.yaml @@ -318,6 +318,7 @@ modules: - src/tests/logger.cpp - src/tests/heap_allocator.cpp - src/tests/main.cpp + - src/tests/vector.cpp overlays: - url: https://f000.backblazeb2.com/file/jsix-os/sysroot-llvm8-20190706.tar.bz2 path: sysroot diff --git a/src/libraries/kutil/include/kutil/vector.h b/src/libraries/kutil/include/kutil/vector.h index 4c5616b..ea27a37 100644 --- a/src/libraries/kutil/include/kutil/vector.h +++ b/src/libraries/kutil/include/kutil/vector.h @@ -3,6 +3,7 @@ /// Definition of a simple dynamic vector collection for use in kernel space #include +#include "kutil/assert.h" #include "kutil/memory.h" namespace kutil { @@ -104,13 +105,66 @@ public: return m_elements[m_size++]; } + /// Insert an item into the array at the given index + void insert(size_t i, const T& item) + { + if (i >= count()) { + append(item); + return; + } + + ensure_capacity(m_size + 1); + for (size_t j = m_size; j > i; --j) + m_elements[j] = m_elements[j-1]; + m_size += 1; + + m_elements[i] = item; + } + + /// Insert an item into the list in a sorted position. Depends on T + /// having a method `int compare(const T *other)`. + void sorted_insert(const T& item) + { + size_t start = 0; + size_t end = m_size; + while (end > start) { + size_t m = start + (end - start) / 2; + int c = item.compare(&m_elements[m]); + if (c < 0) end = m; + else start = m + 1; + } + + insert(start, item); + } + /// Remove an item from the end of the array. void remove() { + kassert(m_size, "Called remove() on an empty array"); + m_size -= 1; m_elements[m_size].~T(); } + /// Remove an item from the front of the array, preserving order. + void remove_front() + { + kassert(m_size, "Called remove_front() on an empty array"); + remove_at(0); + } + + /// Remove the item at the given index from the array, not + /// order-preserving. + void remove_at(size_t i) + { + if (i >= count()) return; + + m_elements[i].~T(); + for (; i < m_size - 1; ++i) + m_elements[i] = m_elements[i+1]; + m_size -= 1; + } + /// Remove the first occurance of an item from the array, not /// order-preserving. Does nothing if the item is not in the array. void remove_swap(const T &item) @@ -128,14 +182,18 @@ public: void remove_swap_at(size_t i) { if (i >= count()) return; + + m_elements[i].~T(); if (i < m_size - 1) m_elements[i] = m_elements[m_size - 1]; - remove(); + m_size -= 1; } /// Remove an item from the end of the array and return it. T pop() { + kassert(m_size, "Called pop() on an empty array"); + T temp = m_elements[m_size - 1]; remove(); return temp; @@ -144,10 +202,10 @@ public: /// Remove an item from the beginning of the array and return it. T pop_front() { + kassert(m_size, "Called pop_front() on an empty array"); + T temp = m_elements[0]; - for (size_t i = 1; i < m_size; ++i) - m_elements[i-1] = m_elements[i]; - remove(); + remove_front(); return temp; } diff --git a/src/tests/container_helpers.h b/src/tests/container_helpers.h new file mode 100644 index 0000000..cee6d35 --- /dev/null +++ b/src/tests/container_helpers.h @@ -0,0 +1,13 @@ +#pragma once + +struct unsortableT { + int value; +}; + +struct sortableT { + int value; + int compare(const sortableT *other) const { + return value - other->value; + } +}; + diff --git a/src/tests/linked_list.cpp b/src/tests/linked_list.cpp index 83ccf45..6f28f56 100644 --- a/src/tests/linked_list.cpp +++ b/src/tests/linked_list.cpp @@ -5,22 +5,12 @@ #include #include "kutil/linked_list.h" #include "catch.hpp" +#include "container_helpers.h" using namespace kutil; const int test_list_size = 100; -struct unsortableT { - int value; -}; - -struct sortableT { - int value; - int compare(const sortableT *other) { - return value - other->value; - } -}; - template class ListVectorCompare : public Catch::MatcherBase>> diff --git a/src/tests/vector.cpp b/src/tests/vector.cpp new file mode 100644 index 0000000..5c8866b --- /dev/null +++ b/src/tests/vector.cpp @@ -0,0 +1,25 @@ +#include +#include "kutil/vector.h" +#include "catch.hpp" +#include "container_helpers.h" + +TEST_CASE( "sorted vector tests", "[containers] [vector]" ) +{ + using clock = std::chrono::system_clock; + unsigned seed = clock::now().time_since_epoch().count(); + std::default_random_engine rng(seed); + std::uniform_int_distribution distrib(0,10000); + + kutil::vector v; + + int sizes[] = {1, 2, 3, 5, 100}; + for (int s : sizes) { + for (int i = 0; i < s; ++i) { + sortableT t { distrib(rng) }; + v.sorted_insert(t); + } + + for (int i = 1; i < s; ++i) + CHECK( v[i].value >= v[i-1].value ); + } +}