comparison foosdk/sdk/foobar2000/helpers/notifyList.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #pragma once
2
3 #include <vector>
4 #include <set>
5 #include <map>
6 #include <memory>
7 #include <pfc/synchro.h>
8
9 template<typename obj_t> class notifyList : public std::vector<obj_t*> {
10 public:
11 void operator+=( obj_t * obj ) { this->push_back(obj); }
12 void operator-=( obj_t * obj ) {
13 for(auto i = this->begin(); i != this->end(); ++i) {
14 if (*i == obj) {this->erase(i); return;}
15 }
16 PFC_ASSERT(!"Should not get here");
17 }
18 bool contains(obj_t* obj) const {
19 for (auto i : *this) {
20 if (i == obj) return true;
21 }
22 return false;
23 }
24 };
25
26
27
28 // Efficient notifylist. Efficient addremove, ordered operation.
29 template<typename obj_t> class notifyList2 {
30 public:
31 typedef uint64_t key_t;
32 typedef obj_t * val_t;
33
34 void add( obj_t * obj ) {
35 auto key = m_increment++;
36 m_ordered[key] = obj;
37 m_unordered[obj] = key;
38 }
39 void remove(obj_t * obj) {
40 auto i1 = m_unordered.find(obj);
41 if (i1 != m_unordered.end()) {
42 m_ordered.erase(i1->second);
43 m_unordered.erase(i1);
44 }
45 }
46 void operator+=(obj_t * obj) {add(obj);}
47 void operator-=(obj_t * obj) {remove(obj);}
48
49 typedef std::vector<obj_t*> state_t;
50
51 state_t get() const {
52 state_t ret;
53 ret.resize(m_ordered.size());
54 size_t walk = 0;
55 for( auto i = m_ordered.begin(); i != m_ordered.end(); ++i ) {
56 ret[walk++] = i->second;
57 }
58 return std::move(ret);
59 }
60 size_t size() const { return m_unordered.size(); }
61 bool contains( obj_t * obj ) const { return m_unordered.find( obj ) != m_unordered.end(); }
62
63 key_t firstKey() const {
64 auto iter = m_ordered.begin();
65 if (iter == m_ordered.end()) return keyInvalid();
66 return iter->first;
67 }
68 key_t nextKey(key_t key) const {
69 auto iter = m_ordered.upper_bound( key );
70 if (iter == m_ordered.end()) return keyInvalid();
71 return iter->first;
72 }
73 obj_t * resolveKey( key_t key ) const {
74 auto iter = m_ordered.find( key );
75 if (iter != m_ordered.end()) return iter->second;
76 return nullptr;
77 }
78 bool validKey(key_t key) const {
79 return m_ordered.find( key ) != m_ordered.end();
80 }
81 static key_t keyInvalid() { return (key_t)(-1); }
82 private:
83
84 key_t m_increment;
85
86 std::map<key_t, val_t> m_ordered;
87 std::map<val_t, key_t> m_unordered;
88 };
89
90 template<typename obj_t> class notifyListUnordered : public std::set<obj_t*> {
91 public:
92 void operator+=( obj_t * obj ) {
93 this->insert( obj );
94 }
95 void operator-=( obj_t * obj ) {
96 this->erase( obj );
97 }
98 };
99
100 //! Notify list v3 \n
101 //! Traits: \n
102 //! * Ordered \n
103 //! * Efficient add/remove \n
104 //! * Handles every possible scenario of add/remove in mid enumeration \n
105 //! * Use begin()/end() to walk with no further workarounds \n
106 //! * If you've done anything between ++ and *iter - or are using the notifylist in multiple threads, check *iter for giving you a null. Otherwise, after ++ you always have a valid value, or end. \n
107 //! Available in two flavours, non thread safe (notifyList3<>) and thread safe (notifyList3MT<>). \n
108 //! Multi threaded version ensures thread safety internally - though once it gives you a pointer, there's no safeguard against removal attempt while the pointer is being used, hence not adivsed.
109 template<typename obj_t, typename sync_t> class notifyList3_ {
110 private:
111 typedef notifyList3_<obj_t, sync_t> self_t;
112 typedef notifyList2< obj_t > content_t;
113 public:
114 typedef typename content_t::key_t contentKey_t;
115 struct data_t {
116 content_t content;
117 sync_t sync;
118 };
119
120 typedef std::shared_ptr< data_t > dataRef_t;
121
122 notifyList3_( ) : m_data(std::make_shared< data_t >()) {}
123
124 void operator+=( obj_t * obj ) { add(obj); }
125 void operator-=( obj_t * obj ) { remove(obj); }
126
127 void add( obj_t * obj ) {
128 inWriteSync( m_data->sync );
129 m_data->content.add( obj );
130 }
131 void remove( obj_t * obj ) {
132 inWriteSync( m_data->sync );
133 m_data->content.remove( obj );
134 }
135 size_t size() const {
136 inReadSync( m_data->sync );
137 return m_data->content.size();
138 }
139
140 class const_iterator {
141 public:
142
143 const_iterator( dataRef_t ref, contentKey_t key ) : m_data(ref), m_key(key) {
144 }
145
146 const_iterator const & operator++(int) {
147 increment();
148 return *this;
149 }
150 const_iterator operator++() {
151 const_iterator ret ( *this );
152 increment();
153 return std::move(ret);
154 }
155
156 void increment() {
157 PFC_ASSERT( isValid() );
158 inReadSync( m_data->sync );
159 m_key = m_data->content.nextKey( m_key );
160 }
161
162 bool isValid() const {
163 inReadSync( m_data->sync );
164 return m_data->content.validKey( m_key );
165 }
166
167 bool operator==( const_iterator const & other ) const {
168 return equals( *this, other );
169 }
170 bool operator!=( const_iterator const & other ) const {
171 return !equals( *this, other );
172 }
173
174 static bool equals( const_iterator const & i1, const_iterator const & i2 ) {
175 return i1.m_key == i2.m_key;
176 }
177
178 //! Returns the referenced value. Will be null in case of invalidation in mid-enumeration.
179 obj_t * operator*() const {
180 inReadSync( m_data->sync );
181 return m_data->content.resolveKey( m_key );
182 }
183
184 private:
185 const_iterator() = delete;
186
187 const dataRef_t m_data;
188 contentKey_t m_key;
189 };
190
191 const_iterator begin() const {
192 inReadSync( m_data->sync );
193 return const_iterator( m_data, m_data->content.firstKey() );
194 }
195 const_iterator end() const {
196 inReadSync( m_data->sync );
197 return const_iterator( m_data, content_t::keyInvalid() );
198 }
199
200 private:
201 notifyList3_( const self_t & ) = delete;
202 void operator=( const self_t & ) = delete;
203
204
205 const dataRef_t m_data;
206 };
207
208 //! Thread safe notifyList3. \n
209 //! See: notifyList3_
210 template<typename obj_t>
211 class notifyList3MT : public notifyList3_<obj_t, pfc::readWriteLock> {
212 public:
213
214 };
215
216 //! Non-thread-safe notifyList3. \n
217 //! See: notifyList3_
218 template<typename obj_t>
219 class notifyList3 : public notifyList3_<obj_t, pfc::dummyLock> {
220 public:
221
222 };