Mercurial > foo_out_sdl
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/helpers/notifyList.h Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,222 @@ +#pragma once + +#include <vector> +#include <set> +#include <map> +#include <memory> +#include <pfc/synchro.h> + +template<typename obj_t> class notifyList : public std::vector<obj_t*> { +public: + void operator+=( obj_t * obj ) { this->push_back(obj); } + void operator-=( obj_t * obj ) { + for(auto i = this->begin(); i != this->end(); ++i) { + if (*i == obj) {this->erase(i); return;} + } + PFC_ASSERT(!"Should not get here"); + } + bool contains(obj_t* obj) const { + for (auto i : *this) { + if (i == obj) return true; + } + return false; + } +}; + + + +// Efficient notifylist. Efficient addremove, ordered operation. +template<typename obj_t> class notifyList2 { +public: + typedef uint64_t key_t; + typedef obj_t * val_t; + + void add( obj_t * obj ) { + auto key = m_increment++; + m_ordered[key] = obj; + m_unordered[obj] = key; + } + void remove(obj_t * obj) { + auto i1 = m_unordered.find(obj); + if (i1 != m_unordered.end()) { + m_ordered.erase(i1->second); + m_unordered.erase(i1); + } + } + void operator+=(obj_t * obj) {add(obj);} + void operator-=(obj_t * obj) {remove(obj);} + + typedef std::vector<obj_t*> state_t; + + state_t get() const { + state_t ret; + ret.resize(m_ordered.size()); + size_t walk = 0; + for( auto i = m_ordered.begin(); i != m_ordered.end(); ++i ) { + ret[walk++] = i->second; + } + return std::move(ret); + } + size_t size() const { return m_unordered.size(); } + bool contains( obj_t * obj ) const { return m_unordered.find( obj ) != m_unordered.end(); } + + key_t firstKey() const { + auto iter = m_ordered.begin(); + if (iter == m_ordered.end()) return keyInvalid(); + return iter->first; + } + key_t nextKey(key_t key) const { + auto iter = m_ordered.upper_bound( key ); + if (iter == m_ordered.end()) return keyInvalid(); + return iter->first; + } + obj_t * resolveKey( key_t key ) const { + auto iter = m_ordered.find( key ); + if (iter != m_ordered.end()) return iter->second; + return nullptr; + } + bool validKey(key_t key) const { + return m_ordered.find( key ) != m_ordered.end(); + } + static key_t keyInvalid() { return (key_t)(-1); } +private: + + key_t m_increment; + + std::map<key_t, val_t> m_ordered; + std::map<val_t, key_t> m_unordered; +}; + +template<typename obj_t> class notifyListUnordered : public std::set<obj_t*> { +public: + void operator+=( obj_t * obj ) { + this->insert( obj ); + } + void operator-=( obj_t * obj ) { + this->erase( obj ); + } +}; + +//! Notify list v3 \n +//! Traits: \n +//! * Ordered \n +//! * Efficient add/remove \n +//! * Handles every possible scenario of add/remove in mid enumeration \n +//! * Use begin()/end() to walk with no further workarounds \n +//! * 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 +//! Available in two flavours, non thread safe (notifyList3<>) and thread safe (notifyList3MT<>). \n +//! 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. +template<typename obj_t, typename sync_t> class notifyList3_ { +private: + typedef notifyList3_<obj_t, sync_t> self_t; + typedef notifyList2< obj_t > content_t; +public: + typedef typename content_t::key_t contentKey_t; + struct data_t { + content_t content; + sync_t sync; + }; + + typedef std::shared_ptr< data_t > dataRef_t; + + notifyList3_( ) : m_data(std::make_shared< data_t >()) {} + + void operator+=( obj_t * obj ) { add(obj); } + void operator-=( obj_t * obj ) { remove(obj); } + + void add( obj_t * obj ) { + inWriteSync( m_data->sync ); + m_data->content.add( obj ); + } + void remove( obj_t * obj ) { + inWriteSync( m_data->sync ); + m_data->content.remove( obj ); + } + size_t size() const { + inReadSync( m_data->sync ); + return m_data->content.size(); + } + + class const_iterator { + public: + + const_iterator( dataRef_t ref, contentKey_t key ) : m_data(ref), m_key(key) { + } + + const_iterator const & operator++(int) { + increment(); + return *this; + } + const_iterator operator++() { + const_iterator ret ( *this ); + increment(); + return std::move(ret); + } + + void increment() { + PFC_ASSERT( isValid() ); + inReadSync( m_data->sync ); + m_key = m_data->content.nextKey( m_key ); + } + + bool isValid() const { + inReadSync( m_data->sync ); + return m_data->content.validKey( m_key ); + } + + bool operator==( const_iterator const & other ) const { + return equals( *this, other ); + } + bool operator!=( const_iterator const & other ) const { + return !equals( *this, other ); + } + + static bool equals( const_iterator const & i1, const_iterator const & i2 ) { + return i1.m_key == i2.m_key; + } + + //! Returns the referenced value. Will be null in case of invalidation in mid-enumeration. + obj_t * operator*() const { + inReadSync( m_data->sync ); + return m_data->content.resolveKey( m_key ); + } + + private: + const_iterator() = delete; + + const dataRef_t m_data; + contentKey_t m_key; + }; + + const_iterator begin() const { + inReadSync( m_data->sync ); + return const_iterator( m_data, m_data->content.firstKey() ); + } + const_iterator end() const { + inReadSync( m_data->sync ); + return const_iterator( m_data, content_t::keyInvalid() ); + } + +private: + notifyList3_( const self_t & ) = delete; + void operator=( const self_t & ) = delete; + + + const dataRef_t m_data; +}; + +//! Thread safe notifyList3. \n +//! See: notifyList3_ +template<typename obj_t> +class notifyList3MT : public notifyList3_<obj_t, pfc::readWriteLock> { +public: + +}; + +//! Non-thread-safe notifyList3. \n +//! See: notifyList3_ +template<typename obj_t> +class notifyList3 : public notifyList3_<obj_t, pfc::dummyLock> { +public: + +};
