source: src/Common/ScopedMap.hpp@ b28ce93

Last change on this file since b28ce93 was 6b33e89, checked in by Peter A. Buhr <pabuhr@…>, 5 months ago

change backquote call to regular call

  • Property mode set to 100644
File size: 11.5 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ScopedMap.hpp --
8//
9// Author : Aaron B. Moss
10// Created On : Wed Dec 2 11:37:00 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Mon May 13 07:32:09 2024
13// Update Count : 6
14//
15
16#pragma once
17
18#include <cassert>
19#include <iterator>
20#include <map>
21#include <utility>
22#include <vector>
23
24/// Default (empty) ScopedMap note type
25struct EmptyNote {};
26
27/// A map where the items are placed into nested scopes;
28/// inserted items are placed into the innermost scope, lookup looks from the innermost scope outward.
29/// Scopes may be annotated with a value; the annotation defaults to empty
30template<typename Key, typename Value, typename Note = EmptyNote>
31class ScopedMap {
32 typedef std::map< Key, Value > MapType;
33public:
34 struct Scope {
35 MapType map;
36 Note note;
37
38 template<typename N>
39 Scope(N && n) : map(), note(std::forward<N>(n)) {}
40
41 Scope() = default;
42 Scope(const Scope &) = default;
43 Scope(Scope &&) = default;
44 Scope & operator= (const Scope &) = default;
45 Scope & operator= (Scope &&) = default;
46 };
47 private:
48 typedef std::vector< Scope > ScopeList;
49
50 /// Scoped list of maps.
51 ScopeList scopes;
52public:
53 typedef typename MapType::key_type key_type;
54 typedef typename MapType::mapped_type mapped_type;
55 typedef typename MapType::value_type value_type;
56 typedef typename ScopeList::size_type size_type;
57 typedef typename ScopeList::difference_type difference_type;
58 typedef typename MapType::reference reference;
59 typedef typename MapType::const_reference const_reference;
60 typedef typename MapType::pointer pointer;
61 typedef typename MapType::const_pointer const_pointer;
62
63 // Both iterator types are complete bidrectional iterators, see below.
64 class iterator;
65 class const_iterator;
66
67 /// Starts a new scope
68 void beginScope() {
69 scopes.emplace_back();
70 }
71
72 // Starts a new scope with the given note
73 template<typename N>
74 void beginScope( N && n ) {
75 scopes.emplace_back( std::forward<N>(n) );
76 }
77
78 /// Ends a scope; invalidates any iterators pointing to elements of that scope
79 void endScope() {
80 scopes.pop_back();
81 assert( ! scopes.empty() );
82 }
83
84 /// Default constructor initializes with one scope
85 ScopedMap() : scopes() { beginScope(); }
86
87 /// Constructs with a given note on the outermost scope
88 template<typename N>
89 ScopedMap( N && n ) : scopes() { beginScope(std::forward<N>(n)); }
90
91 iterator begin() { return iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
92 const_iterator begin() const { return const_iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
93 const_iterator cbegin() const { return const_iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
94 iterator end() { return iterator(scopes, scopes[0].map.end(), 0); }
95 const_iterator end() const { return const_iterator(scopes, scopes[0].map.end(), 0); }
96 const_iterator cend() const { return const_iterator(scopes, scopes[0].map.end(), 0); }
97
98 /// Gets the index of the current scope (counted from 1)
99 size_type currentScope() const { return scopes.size() - 1; }
100
101 /// Gets the note at the given scope
102 Note & getNote() { return scopes.back().note; }
103 const Note & getNote() const { return scopes.back().note; }
104 Note & getNote( size_type i ) { return scopes[i].note; }
105 const Note & getNote( size_type i ) const { return scopes[i].note; }
106
107 /// Finds the given key in the outermost scope it occurs; returns end() for none such
108 iterator find( const Key & key ) {
109 for ( size_type i = scopes.size() - 1; ; --i ) {
110 typename MapType::iterator val = scopes[i].map.find( key );
111 if ( val != scopes[i].map.end() ) return iterator( scopes, val, i );
112 if ( i == 0 ) break;
113 }
114 return end();
115 }
116 const_iterator find( const Key & key ) const {
117 return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->find( key ) );
118 }
119
120 /// Finds the given key in the provided scope; returns end() for none such
121 iterator findAt( size_type scope, const Key & key ) {
122 typename MapType::iterator val = scopes[scope].map.find( key );
123 if ( val != scopes[scope].map.end() ) return iterator( scopes, val, scope );
124 return end();
125 }
126 const_iterator findAt( size_type scope, const Key & key ) const {
127 return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findAt( scope, key ) );
128 }
129
130 /// Finds the given key in the outermost scope inside the given scope where it occurs
131 iterator findNext( const_iterator & it, const Key & key ) {
132 if ( it.level == 0 ) return end();
133 for ( size_type i = it.level - 1; ; --i ) {
134 typename MapType::iterator val = scopes[i].map.find( key );
135 if ( val != scopes[i].map.end() ) return iterator( scopes, val, i );
136 if ( i == 0 ) break;
137 }
138 return end();
139 }
140 const_iterator findNext( const_iterator & it, const Key & key ) const {
141 return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findNext( it, key ) );
142 }
143
144 /// Inserts the given key-value pair into the outermost scope
145 template< typename value_type_t >
146 std::pair< iterator, bool > insert( value_type_t && value ) {
147 std::pair< typename MapType::iterator, bool > res = scopes.back().map.insert( std::forward<value_type_t>( value ) );
148 return std::make_pair( iterator(scopes, std::move( res.first ), scopes.size()-1), std::move( res.second ) );
149 }
150
151 template< typename value_t >
152 std::pair< iterator, bool > insert( const Key & key, value_t && value ) { return insert( std::make_pair( key, std::forward<value_t>( value ) ) ); }
153
154 template< typename value_type_t >
155 std::pair< iterator, bool > insertAt( size_type scope, value_type_t && value ) {
156 std::pair< typename MapType::iterator, bool > res = scopes.at(scope).map.insert( std::forward<value_type_t>( value ) );
157 return std::make_pair( iterator(scopes, std::move( res.first ), scope), std::move( res.second ) );
158 }
159
160 template< typename value_t >
161 std::pair< iterator, bool > insertAt( size_type scope, const Key & key, value_t && value ) {
162 return insertAt( scope, std::make_pair( key, std::forward<value_t>( value ) ) );
163 }
164
165 Value & operator[] ( const Key & key ) {
166 iterator slot = find( key );
167 if ( slot != end() ) return slot->second;
168 return insert( key, Value() ).first->second;
169 }
170
171 /// Erases element with key in the innermost scope that has it.
172 size_type erase( const Key & key ) {
173 for ( auto it = scopes.rbegin() ; it != scopes.rend() ; ++it ) {
174 size_type i = it->map.erase( key );
175 if ( 0 != i ) return i;
176 }
177 return 0;
178 }
179
180 size_type count( const Key & key ) const {
181 size_type c = 0;
182 auto it = find( key );
183 auto end = cend();
184
185 while(it != end) {
186 c++;
187 it = findNext(it, key);
188 }
189
190 return c;
191 }
192
193 bool contains( const Key & key ) const {
194 return find( key ) != cend();
195 }
196};
197
198template<typename Key, typename Value, typename Note>
199class ScopedMap<Key, Value, Note>::iterator :
200 public std::iterator< std::bidirectional_iterator_tag, value_type > {
201 friend class ScopedMap;
202 friend class const_iterator;
203 typedef typename MapType::iterator wrapped_iterator;
204 typedef typename ScopeList::size_type size_type;
205
206 /// Checks if this iterator points to a valid item
207 bool is_valid() const {
208 return it != (*scopes)[level].map.end();
209 }
210
211 /// Increments on invalid
212 iterator & next_valid() {
213 if ( ! is_valid() ) { ++(*this); }
214 return *this;
215 }
216
217 /// Decrements on invalid
218 iterator & prev_valid() {
219 if ( ! is_valid() ) { --(*this); }
220 return *this;
221 }
222
223 iterator(ScopeList & _scopes, const wrapped_iterator & _it, size_type inLevel)
224 : scopes(&_scopes), it(_it), level(inLevel) {}
225public:
226 iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
227 iterator & operator= (const iterator & that) {
228 scopes = that.scopes; level = that.level; it = that.it;
229 return *this;
230 }
231
232 reference operator* () { return *it; }
233 pointer operator-> () const { return it.operator->(); }
234
235 iterator & operator++ () {
236 if ( it == (*scopes)[level].map.end() ) {
237 if ( level == 0 ) return *this;
238 --level;
239 it = (*scopes)[level].map.begin();
240 } else {
241 ++it;
242 }
243 return next_valid();
244 }
245 iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
246
247 iterator & operator-- () {
248 // may fail if this is the begin iterator; allowed by STL spec
249 if ( it == (*scopes)[level].map.begin() ) {
250 ++level;
251 it = (*scopes)[level].map.end();
252 }
253 --it;
254 return prev_valid();
255 }
256 iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
257
258 bool operator== (const iterator & that) const {
259 return scopes == that.scopes && level == that.level && it == that.it;
260 }
261 bool operator!= (const iterator & that) const { return !( *this == that ); }
262
263 size_type get_level() const { return level; }
264
265 Note & get_note() { return (*scopes)[level].note; }
266 const Note & get_note() const { return (*scopes)[level].note; }
267
268private:
269 ScopeList *scopes;
270 wrapped_iterator it;
271 size_type level;
272};
273
274template<typename Key, typename Value, typename Note>
275class ScopedMap<Key, Value, Note>::const_iterator :
276 public std::iterator< std::bidirectional_iterator_tag, value_type > {
277 friend class ScopedMap;
278 typedef typename ScopedMap::MapType::iterator wrapped_iterator;
279 typedef typename ScopedMap::MapType::const_iterator wrapped_const_iterator;
280 typedef typename ScopedMap::ScopeList scope_list;
281 typedef typename scope_list::size_type size_type;
282
283 /// Checks if this iterator points to a valid item
284 bool is_valid() const {
285 return it != (*scopes)[level].map.end();
286 }
287
288 /// Increments on invalid
289 const_iterator & next_valid() {
290 if ( ! is_valid() ) { ++(*this); }
291 return *this;
292 }
293
294 /// Decrements on invalid
295 const_iterator & prev_valid() {
296 if ( ! is_valid() ) { --(*this); }
297 return *this;
298 }
299
300 const_iterator(scope_list const & _scopes, const wrapped_const_iterator & _it, size_type inLevel)
301 : scopes(&_scopes), it(_it), level(inLevel) {}
302public:
303 const_iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
304 const_iterator(const const_iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
305 const_iterator & operator= (const iterator & that) {
306 scopes = that.scopes; level = that.level; it = that.it;
307 return *this;
308 }
309 const_iterator & operator= (const const_iterator & that) {
310 scopes = that.scopes; level = that.level; it = that.it;
311 return *this;
312 }
313
314 const_reference operator* () { return *it; }
315 const_pointer operator-> () { return it.operator->(); }
316
317 const_iterator & operator++ () {
318 if ( it == (*scopes)[level].map.end() ) {
319 if ( level == 0 ) return *this;
320 --level;
321 it = (*scopes)[level].map.begin();
322 } else {
323 ++it;
324 }
325 return next_valid();
326 }
327 const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
328
329 const_iterator & operator-- () {
330 // may fail if this is the begin iterator; allowed by STL spec
331 if ( it == (*scopes)[level].map.begin() ) {
332 ++level;
333 it = (*scopes)[level].map.end();
334 }
335 --it;
336 return prev_valid();
337 }
338 const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
339
340 bool operator== (const const_iterator & that) const {
341 return scopes == that.scopes && level == that.level && it == that.it;
342 }
343 bool operator!= (const const_iterator & that) const { return !( *this == that ); }
344
345 size_type get_level() const { return level; }
346
347 const Note & get_note() const { return (*scopes)[level].note; }
348
349private:
350 scope_list const *scopes;
351 wrapped_const_iterator it;
352 size_type level;
353};
354
355// Local Variables: //
356// tab-width: 4 //
357// mode: c++ //
358// compile-command: "make install" //
359// End: //
Note: See TracBrowser for help on using the repository browser.