Ticket #9223: anyvalueset.hpp

File anyvalueset.hpp, 4.9 KB (added by mjklaim@…, 9 years ago)

Example of real-world code that would be simplified by the feature.

Line 
1#ifndef HGUARD_NETRUSH_VIEW_ANYVALUESET_HPP__
2#define HGUARD_NETRUSH_VIEW_ANYVALUESET_HPP__
3
4#include <memory>
5#include <typeindex>
6#include <vector>
7
8#include <boost/container/flat_map.hpp>
9#include <boost/container/flat_set.hpp>
10#include <boost/optional.hpp>
11
12
13namespace netrush {
14namespace view {
15
16
17 class AnyValueSet
18 {
19 public:
20
21 template< class ValueType >
22 void add( ValueType value )
23 {
24 auto& flag_set = find_or_create_set<ValueType>();
25 flag_set.add( std::move(value) );
26 m_size_changed = true;
27 }
28
29 template< class ValueType >
30 void remove( const ValueType& value )
31 {
32 if( auto* flag_set = find_set<ValueType>() )
33 {
34 flag_set->remove( std::forward<ValueType>( value ) );
35 m_size_changed = true;
36 }
37 }
38
39 template< class ValueType, class KeyType >
40 boost::optional<ValueType> find( const KeyType& key ) const
41 {
42 if( auto* flag_set = find_set<ValueType>() )
43 {
44 return flag_set->find( key );
45 }
46 return {};
47 }
48
49 template< class ValueType >
50 boost::optional<ValueType> find( const ValueType& value ) const
51 {
52 return find<ValueType, ValueType>( value );
53 }
54
55
56 template< class ValueType, class KeyType >
57 bool contains( const KeyType& key ) const
58 {
59 if( auto* flag_set = find_set<ValueType>() )
60 {
61 return flag_set->contains( key );
62 }
63 return false;
64 }
65
66 template< class ValueType >
67 bool contains( const ValueType& value ) const
68 {
69 return contains<ValueType, ValueType>( value );
70 }
71
72
73 void insert( const AnyValueSet& other )
74 {
75 for( const auto& set_pair : other.m_set_index )
76 {
77 if( auto flag_set = find_set( set_pair.first ) )
78 {
79 flag_set->insert( *set_pair.second );
80 }
81 else
82 {
83 m_set_index.emplace( set_pair.first, set_pair.second->clone() );
84 }
85 }
86 m_size_changed = true;
87 }
88
89
90 template< class ValueType >
91 std::vector<ValueType> all() const
92 {
93 if( auto* flag_set = find_set<ValueType>() )
94 {
95 return flag_set->values();
96 }
97 return {};
98 }
99
100 size_t size() const
101 {
102 if( m_size_changed )
103 {
104 m_size_changed = false;
105 compute_size();
106 }
107
108 return m_size;
109 }
110
111 private:
112
113 struct Set
114 {
115 virtual void insert( const Set& other ) = 0;
116 virtual std::unique_ptr<Set> clone() = 0;
117 virtual size_t size() const = 0;
118 };
119
120 template< class T >
121 class SetOf : public Set
122 {
123 boost::container::flat_set<T> m_values;
124 public:
125 SetOf() = default;
126
127 template< class Iterator >
128 SetOf( Iterator&& it_begin, Iterator&& it_end )
129 : m_values( std::forward<Iterator>( it_begin ), std::forward<Iterator>( it_end ) )
130 {}
131
132 /** Add a new value or replace an old one by the provided one.
133 */
134 void add( T value )
135 {
136 auto result = m_values.emplace( std::move( value ) );
137 if( !result.second ) // force overwriting if the value already exists
138 *result.first = value;
139 }
140 void remove( T value ) { m_values.erase( std::move( value ) ); }
141
142 template< class KeyType >
143 boost::optional<T> find( const KeyType& key ) const
144 {
145 for( const auto& value : m_values )
146 {
147 if( value == key )
148 return value;
149 }
150
151 return {};
152 }
153
154 template< class KeyType >
155 bool contains( const KeyType& key ) const
156 {
157 for( const auto& value : m_values )
158 {
159 if( value == key )
160 return true;
161 }
162
163 return false;
164 }
165
166 void insert( const Set& other ) override
167 {
168 const auto& specific_set = static_cast<const SetOf<T>&>( other );
169 m_values.insert( begin( specific_set.m_values ), end( specific_set.m_values ) );
170 }
171
172 std::unique_ptr<Set> clone() override
173 {
174 return std::make_unique<SetOf<T>>( begin( m_values ), end( m_values ) );
175 }
176
177 size_t size() const override { return m_values.size(); }
178
179 std::vector<T> values() const
180 {
181 return { begin( m_values ), end( m_values ) };
182 }
183 };
184
185 boost::container::flat_map<std::type_index, std::shared_ptr<Set>> m_set_index;
186 mutable bool m_size_changed = false;
187 mutable size_t m_size = 0;
188
189
190 Set* find_set( std::type_index type_id ) const
191 {
192 auto find_it = m_set_index.find( type_id );
193 if( find_it != end( m_set_index ) )
194 {
195 auto& specific_set = *find_it->second;
196 return &specific_set;
197 }
198 return nullptr;
199 }
200
201
202 template< class T >
203 SetOf<T>* find_set() const { return static_cast<SetOf<T>*>( find_set( typeid( T ) ) ); }
204
205 template< class T >
206 SetOf<T>& find_or_create_set()
207 {
208 if( auto* specific_set = find_set<T>() )
209 {
210 return *specific_set;
211 }
212
213 auto position = m_set_index.emplace( typeid( T ), std::make_shared < SetOf < T >> ( ) ).first;
214 return static_cast<SetOf<T>&>( *position->second );
215 }
216
217 void compute_size() const
218 {
219 m_size = 0;
220 for( const auto& set_pair : m_set_index )
221 {
222 m_size += set_pair.second->size();
223 }
224 }
225
226 };
227
228
229}}
230
231
232#endif