-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathscopedmap.hpp
121 lines (102 loc) · 3.97 KB
/
scopedmap.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright Morten Bendiksen 2014 - 2016.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#ifndef MEDIASEQUENCER_PLUGIN_UTIL_XPATH_SCOPEDMAP_HPP
#define MEDIASEQUENCER_PLUGIN_UTIL_XPATH_SCOPEDMAP_HPP
#include <boost/noncopyable.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional.hpp>
#include <unordered_map>
#include <algorithm>
#include <memory>
#include <assert.h>
namespace mediasequencer { namespace plugin { namespace util { namespace xpath {
template <class K, class V>
class scopedmap {
private:
struct scope: boost::noncopyable {
std::shared_ptr<scope> parent;
unsigned identifier;
std::vector<K> keys;
std::unordered_map<K, std::vector<std::pair<unsigned, V> > > & map;
scope(std::shared_ptr<scope> parent,
unsigned identifier,
std::unordered_map<K, std::vector<std::pair<unsigned, V> > > & map): parent(std::move(parent)),
identifier(identifier), map(map){
}
static unsigned get_first(std::pair<unsigned, V> const& p) {
return p.first;
};
~scope() {
for (auto& k : keys) {
auto i = map.find(k);
assert(i != map.end());
auto begin = boost::make_transform_iterator(i->second.begin(), get_first);
auto end = boost::make_transform_iterator(i->second.end(), get_first);
auto j = std::lower_bound(begin, end, identifier);
assert(j != end);
i->second.erase(j.base());
}
}
};
std::shared_ptr<std::pair<unsigned, std::unordered_map<K, std::vector<std::pair<unsigned, V> > > > > shared;
std::shared_ptr<scope> s;
public:
scopedmap() :
shared(new std::pair<unsigned, std::unordered_map<K, std::vector<std::pair<unsigned, V> > > >()),
s(new scope(std::shared_ptr<scope>(), 0u, shared->second))
{ shared->first = 1u; }
scopedmap(scopedmap const& other): shared(other.shared), s(other.s) {}
scopedmap(scopedmap&& other): shared(std::move(other.shared)),s(std::move(other.s)) {}
scopedmap& operator=(scopedmap&& other) {
std::swap(shared, other.shared);
std::swap(s, other.s);
return *this;
}
scopedmap& operator=(scopedmap const& other) {
shared = other.shared;
s = other.s;
return *this;
}
private:
scopedmap(
std::shared_ptr<std::pair<unsigned, std::unordered_map<K, std::vector<std::pair<unsigned, V> > > > > shared,
std::shared_ptr<scope> new_scope)
: shared(std::move(shared)), s(std::move(new_scope))
{
}
public:
template <typename Iterator>
scopedmap add(Iterator begin, Iterator end) {
if(begin == end)return *this;
std::shared_ptr<scope> new_scope(new scope(s, (shared->first), (shared->second)));
for (; begin != end; ++begin) {
new_scope->keys.push_back(begin->first);
shared->second[begin->first].push_back(std::make_pair(shared->first, begin->second));
}
(shared->first)++;
return scopedmap(shared, std::move(new_scope));
}
boost::optional<const V&> const get(K const& k) const {
scope* current = s.get();
auto i = shared->second.find(k);
if (i == shared->second.end())
return boost::optional<const V&>();
auto& vect = i->second;
auto j = vect.rbegin();
while (current && j != vect.rend()) {
if (current->identifier > j->first) {
current = current->parent.get();
} else if (current->identifier < j->first) {
++j;
} else {
return boost::optional<const V&>(j->second);
}
}
return boost::optional<const V&>();
}
};
}}}}
#endif // MEDIASEQUENCER_PLUGIN_UTIL_XPATH_SCOPEDMAP_HPP