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