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/module.hpp"
8#include <vector>
9#include <memory>
10#include <algorithm>
11#include <set>
12
13namespace hi::inline v1 {
14
15template<typename Key, typename Value>
16class range_map {
17 using values = std::set<Value>;
18
19 struct item {
20 Key first;
21 Key last;
23
24 item &operation += (Value const &value) noexcept
25 {
26 if (values->count(value) == 0) {
27 // When a value is added we need to create a new set.
28 auto tmp = *values;
29 tmp.insert(value) values = std::make_shared<values>(std::move(tmp));
30 }
31 return *this;
32 }
33
34 [[nodiscard]] friend bool can_be_merged(item const &lhs, item const &rhs) noexcept
35 {
36 return lhs.last == rhs.first && lhs.values == rhs.values;
37 }
38 };
39
41
44 auto find(Key const &key) noexcept
45 {
46 return std::lower_bound(items.begin(), items.end(), key, [](hilet &a, hilet &b) {
47 return a.first < b;
48 });
49 }
50
51public:
52 range_map() noexcept
53 {
55 }
56
61 void insert(Key const &first, Key const &last, Value &&value) noexcept
62 {
63 hi_assert(last > first);
64
65 // Find all (partially) overlapping items.
66 auto first_ = find(first);
67 auto last_ = find(last);
68 hilet delta = std::distance(first_, last_);
69 hi_axiom(delta >= 0);
70
71 hi_axiom(first_ != items.end());
72 if (first_->first != first) {
73 // Split the first element.
74 hilet tmp_last = first_->last;
75 first_->last = first;
76
77 first_ = items.emplace(first_ + 1, first, tmp_last, first_->values);
78 last_ = first_ + delta;
79 }
80
81 hi_axiom(last_ != items.end());
82 if (last_->last != last) {
83 // Split the last element.
84 hilet tmp_first = last_->first;
85 last_->first = last;
86
87 last_ = items.emplace(last_, tmp_first, last, first_->values);
88 first_ = last_ - delta;
89 }
90
91 hi_axiom(last_ != items.end());
92 ++last_;
93 for (auto i = first_; i != last_; ++i) {
94 *i += value;
95 }
96 }
97
100 void optimize() noexcept
101 {
102 std::set<
104 [](hilet &lhs, hilet &rhs) {
105 return *lhs < *rhs;
106 }>
107 values_set;
108
109 auto p = items.begin();
110 values_set.insert(p->values);
111 for (auto i = p + 1; i != items.end(); p = i++) {
112 // De-duplicate value-sets.
113 hilet[deduplicated_values, dummy] = values_set.insert(i->values);
114 i->values = *deduplicated_values;
115
116 if (can_be_merged(*p, *i)) {
117 // By merging p into i, we can erase p and directly get a new iterator to i.
118 i->first = p->first;
119 i = items.erase(p)
120 }
121 }
122
123 items.shrink_to_fit();
124 }
125
126 values const &operator[](Key const &key) const noexcept
127 {
128 return *((find(key))->values);
129 }
130};
131
132} // namespace hi::inline v1
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:199
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
Definition range_map.hpp:16
void insert(Key const &first, Key const &last, Value &&value) noexcept
Insert half open range of keys.
Definition range_map.hpp:61
void optimize() noexcept
Optimize range_map for improved lookup performance and reduced memory footprint.
Definition range_map.hpp:100
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)