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