From acf81b368aa4a1e7f9fbac5facd93ef1dfc5a877 Mon Sep 17 00:00:00 2001
From: Patrick Wuttke
Date: Tue, 17 Feb 2026 10:25:26 +0100
Subject: [PATCH] Added SortedVector class.
---
source/mijin/container/sorted_vector.hpp | 126 +++++++++++++++++++++++
1 file changed, 126 insertions(+)
create mode 100644 source/mijin/container/sorted_vector.hpp
diff --git a/source/mijin/container/sorted_vector.hpp b/source/mijin/container/sorted_vector.hpp
new file mode 100644
index 0000000..dc54905
--- /dev/null
+++ b/source/mijin/container/sorted_vector.hpp
@@ -0,0 +1,126 @@
+
+#pragma once
+
+#if !defined(MIJIN_CONTAINER_SORTED_VECTOR_HPP_INCLUDED)
+#define MIJIN_CONTAINER_SORTED_VECTOR_HPP_INCLUDED 1
+
+#include
+#include
+#include
+#include "../util/functional.hpp"
+
+namespace mijin
+{
+template TProj = std::identity,
+ ordering> TOrder = std::less>>
+class SortedVector
+{
+public:
+ using key_t = projected_t;
+ using base_t = std::vector;
+ using iterator = base_t::const_iterator;
+ using const_iterator = iterator;
+ using reverse_iterator = base_t::const_reverse_iterator;
+ using const_reverse_iterator = reverse_iterator;
+private:
+ std::vector values_;
+ [[no_unique_address]] TProj proj_;
+ [[no_unique_address]] TOrder order_;
+public:
+ explicit SortedVector(TProj proj = {}, TOrder order = {}) noexcept
+ : proj_(std::move(proj)), order_(std::move(order)) {}
+ explicit SortedVector(TOrder order) noexcept
+ : order_(std::move(order)) {}
+ SortedVector(const SortedVector&) = default;
+ SortedVector(SortedVector&&) noexcept = default;
+ explicit SortedVector(std::vector values) : values_(std::move(values))
+ {
+ processValues();
+ }
+ SortedVector& operator=(const SortedVector&) = default;
+ SortedVector& operator=(SortedVector&&) noexcept = default;
+
+ // --- iterators ---
+
+ [[nodiscard]]
+ const_iterator begin() const noexcept { return values_.begin(); }
+
+ [[nodiscard]]
+ const_iterator cbegin() const noexcept { return values_.cbegin(); }
+
+ [[nodiscard]]
+ const_reverse_iterator rbegin() const noexcept { return values_.rbegin(); }
+
+ [[nodiscard]]
+ const_reverse_iterator crbegin() const noexcept { return values_.crbegin(); }
+
+ [[nodiscard]]
+ const_iterator end() const noexcept { return values_.end(); }
+
+ [[nodiscard]]
+ const_iterator cend() const noexcept { return values_.cend(); }
+
+ [[nodiscard]]
+ const_reverse_iterator rend() const noexcept { return values_.rend(); }
+
+ [[nodiscard]]
+ const_reverse_iterator crend() const noexcept { return values_.crend(); }
+
+ // --- reading ---
+ [[nodiscard]]
+ const T& at(std::size_t idx) const noexcept { return values_.at(idx); }
+
+ [[nodiscard]]
+ const T& operator[](std::size_t idx) const noexcept { return at(idx); }
+
+ [[nodiscard]]
+ std::size_t size() const noexcept { return values_.size(); }
+
+ [[nodiscard]]
+ bool empty() const noexcept { return values_.empty(); }
+
+ [[nodiscard]]
+ iterator find(key_t key) const noexcept
+ {
+ auto it = std::ranges::lower_bound(values_, key, order_, proj_);
+ if (it == values_.end() || std::invoke(proj_, *it) != key) {
+ return values_.end();
+ }
+ return it;
+ }
+
+ // --- writing ---
+ void clear()
+ {
+ values_.clear();
+ }
+
+ void emplace(std::vector values)
+ {
+ values_ = std::move(values);
+ processValues();
+ }
+
+ template
+ void appendRange(TRange&& range)
+ {
+ values_.append_range(std::forward(range));
+ processValues();
+ }
+
+ [[nodiscard]]
+ std::vector&& release() && noexcept
+ {
+ return std::exchange(values_, {});
+ }
+private:
+ void processValues()
+ {
+ values_.shrink_to_fit();
+ std::ranges::sort(values_, order_, proj_);
+ }
+};
+} // namespace mijin
+
+#endif // MIJIN_CONTAINER_SORTED_VECTOR_HPP_INCLUDED