HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
range_map.hpp
1// Copyright Take Vos 2020-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "../utility/utility.hpp"
8#include "../macros.hpp"
9#include <vector>
10#include <memory>
11#include <algorithm>
12#include <set>
13
14
15
16namespace hi::inline v1 {
17
18template<typename Key, typename Value>
19class range_map {
20 using values = std::set<Value>;
21
22 struct item {
23 Key first;
24 Key last;
26
27 item &operator += (Value const &value) noexcept
28 {
29 if (values->count(value) == 0) {
30 // When a value is added we need to create a new set.
31 auto tmp = *values;
32 tmp.insert(value) values = std::make_shared<values>(std::move(tmp));
33 }
34 return *this;
35 }
36
37 [[nodiscard]] friend bool can_be_merged(item const &lhs, item const &rhs) noexcept
38 {
39 return lhs.last == rhs.first && lhs.values == rhs.values;
40 }
41 };
42
44
47 auto find(Key const &key) noexcept
48 {
49 return std::lower_bound(items.begin(), items.end(), key, [](hilet &a, hilet &b) {
50 return a.first < b;
51 });
52 }
53
54public:
55 range_map() noexcept
56 {
58 }
59
64 void insert(Key const &first, Key const &last, Value &&value) noexcept
65 {
66 hi_assert(last > first);
67
68 // Find all (partially) overlapping items.
69 auto first_ = find(first);
70 auto last_ = find(last);
71 hilet delta = std::distance(first_, last_);
72 hi_axiom(delta >= 0);
73
74 hi_axiom(first_ != items.end());
75 if (first_->first != first) {
76 // Split the first element.
77 hilet tmp_last = first_->last;
78 first_->last = first;
79
80 first_ = items.emplace(first_ + 1, first, tmp_last, first_->values);
81 last_ = first_ + delta;
82 }
83
84 hi_axiom(last_ != items.end());
85 if (last_->last != last) {
86 // Split the last element.
87 hilet tmp_first = last_->first;
88 last_->first = last;
89
90 last_ = items.emplace(last_, tmp_first, last, first_->values);
91 first_ = last_ - delta;
92 }
93
94 hi_axiom(last_ != items.end());
95 ++last_;
96 for (auto i = first_; i != last_; ++i) {
97 *i += value;
98 }
99 }
100
103 void optimize() noexcept
104 {
105 std::set<
107 [](hilet &lhs, hilet &rhs) {
108 return *lhs < *rhs;
109 }>
110 values_set;
111
112 auto p = items.begin();
113 values_set.insert(p->values);
114 for (auto i = p + 1; i != items.end(); p = i++) {
115 // De-duplicate value-sets.
116 hilet[deduplicated_values, dummy] = values_set.insert(i->values);
117 i->values = *deduplicated_values;
118
119 if (can_be_merged(*p, *i)) {
120 // By merging p into i, we can erase p and directly get a new iterator to i.
121 i->first = p->first;
122 i = items.erase(p)
123 }
124 }
125
126 items.shrink_to_fit();
127 }
128
129 values const &operator[](Key const &key) const noexcept
130 {
131 return *((find(key))->values);
132 }
133};
134
135} // namespace hi::inline v1
DOXYGEN BUG.
Definition algorithm.hpp:16
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Definition range_map.hpp:19
void insert(Key const &first, Key const &last, Value &&value) noexcept
Insert half open range of keys.
Definition range_map.hpp:64
void optimize() noexcept
Optimize range_map for improved lookup performance and reduced memory footprint.
Definition range_map.hpp:103
T begin(T... args)
T count(T... args)
T distance(T... args)
T emplace_back(T... args)
T emplace(T... args)
T end(T... args)
T erase(T... args)
T insert(T... args)
T lower_bound(T... args)
T move(T... args)
T shrink_to_fit(T... args)