HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
range_map.hpp
1// Copyright Take Vos 2020.
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 "required.hpp"
9#include <vector>
10#include <memory>
11#include <algorithm>
12#include <set>
13
14namespace tt {
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 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)
30 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 return lhs.last == rhs.first && lhs.values == rhs.values;
37 }
38 };
39
41
44 auto find(Key const &key) noexcept {
45 return std::lower_bound(items.begin(), items.end(), key, [](ttlet &a, ttlet &b) {
46 return a.first < b;
47 });
48 }
49
50public:
51 range_map() noexcept {
53 }
54
59 void insert(Key const &first, Key const &last, Value &&value) noexcept {
60 tt_assert(last > first);
61
62 // Find all (partially) overlapping items.
63 auto first_ = find(first);
64 auto last_ = find(last);
65 ttlet delta = std::distance(first_, last_);
66 tt_axiom(delta >= 0);
67
68 tt_axiom(first_ != items.end());
69 if (first_->first != first) {
70 // Split the first element.
71 ttlet tmp_last = first_->last;
72 first_->last = first;
73
74 first_ = items.emplace(first_ + 1, first, tmp_last, first_->values);
75 last_ = first_ + delta;
76 }
77
78 tt_axiom(last_ != items.end());
79 if (last_->last != last) {
80 // Split the last element.
81 ttlet tmp_first = last_->first;
82 last_->first = last;
83
84 last_ = items.emplace(last_, tmp_first, last, first_->values);
85 first_ = last_ - delta;
86 }
87
88 tt_axiom(last_ != items.end());
89 ++last_;
90 for (auto i = first_; i != last_; ++i) {
91 *i += value;
92 }
93 }
94
97 void optimize() noexcept {
98 std::set<std::shared_ptr<values>,[](ttlet &lhs, ttlet &rhs) { return *lhs < *rhs; }> values_set;
99
100 auto p = items.begin();
101 values_set.insert(p->values);
102 for (auto i = p + 1; i != items.end(); p = i++) {
103 // De-duplicate value-sets.
104 ttlet [deduplicated_values, dummy] = values_set.insert(i->values);
105 i->values = *deduplicated_values;
106
107 if (can_be_merged(*p, *i)) {
108 // By merging p into i, we can erase p and directly get a new iterator to i.
109 i->first = p->first;
110 i = items.erase(p)
111 }
112 }
113
114 items.shrink_to_fit();
115 }
116
117 values const &operator[](Key const &key) const noexcept {
118 return *((find(key))->values);
119 }
120};
121
122
123}
Definition range_map.hpp:17
void optimize() noexcept
Optimize range_map for improved lookup performance and reduced memory footprint.
Definition range_map.hpp:97
void insert(Key const &first, Key const &last, Value &&value) noexcept
Insert half open range of keys.
Definition range_map.hpp:59
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)