Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/SDK/commonObjects.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/SDK/commonObjects.h Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,298 @@ +#pragma once + +#include <functional> +#include <initializer_list> +#include <pfc/list.h> +#include "completion_notify.h" + +namespace fb2k { + typedef service_ptr objRef; + + template<typename interface_t> class array_typed; + template<typename interface_t> class array_soft_typed; + + class NOVTABLE array : public service_base, public pfc::list_base_const_t<service_ptr> { + FB2K_MAKE_SERVICE_INTERFACE( array, service_base ); + public: + virtual size_t count() const = 0; + size_t size() const {return count();} + virtual objRef itemAt( size_t index ) const = 0; + + objRef firstItem( ) const; + objRef lastItem( ) const; + + objRef operator[] (size_t idx) const {return itemAt(idx);} + + array::ptr arrayReordered( size_t const * order, size_t count ); + + array::ptr copy() const; + //! If this is a mutable array, creates a const copy of it. \n + //! Otherwise returns this object. + array::ptr makeConst() const; + + static array::ptr empty(); + static array::ptr arrayWithArray( array::ptr source ); + static array::ptr arrayWithObject( objRef source ); + static array::ptr arrayWithObjects( objRef const * source, size_t count ); + static array::ptr arrayWithObjects(std::initializer_list< objRef > const&); + + size_t indexOfItem( objRef item ); + + array::ptr subset( pfc::bit_array const & mask ) const; + array::ptr subsetExcluding( pfc::bit_array const & mask ) const; + array::ptr subsetExcludingSingle( size_t index ) const; + + // UNSAFE CAST HELPER + // Use only when documented as allowed + template<typename interface_t> + const pfc::list_base_const_t< service_ptr_t< interface_t > >& as_list_of() const { + const pfc::list_base_const_t<service_ptr> * temp = this; + return *reinterpret_cast<const pfc::list_base_const_t< service_ptr_t< interface_t > > * > (temp); + } + + // TYPED ARRAY HELPER + // Usage: for( auto obj : myArray->typed<interface>() ) { ... } + // Expects ALL objects in the array to implement the interface - causes runtime bugcheck if they don't + template<typename interface_t> + const array_typed<interface_t>& typed() const { return *reinterpret_cast< const array_typed<interface_t> * > (this); } + + // SOFT TYPED ARRAY HELPER + // Usage: for( auto obj : myArray->softTyped<interface>() ) { ... } + // Skips objects not implementing the interface. + template<typename interface_t> + const array_soft_typed<interface_t>& softTyped() const { return *reinterpret_cast<const array_soft_typed<interface_t> *> (this); } + + + // pfc::list_base_const_t<> + t_size get_count() const override {return this->count();} + void get_item_ex(service_ptr& p_out, t_size n) const override { p_out = this->itemAt(n); } + }; + + template<typename interface_t> class array_typed : public array { + public: + typedef service_ptr_t<interface_t> ptr_t; + class iterator { + public: + static iterator _make(const array* arr, size_t index) { iterator ret; ret.m_arr = arr; ret.m_index = index; return ret; } + void operator++() { ++m_index; } + bool operator==(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index == other.m_index; } + bool operator!=(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index != other.m_index; } + + ptr_t operator*() const { + ptr_t ret; + ret ^= m_arr->itemAt(m_index); + return ret; + } + private: + const array* m_arr; + size_t m_index; + }; + typedef iterator const_iterator; + iterator begin() const { return iterator::_make(this, 0); } + iterator end() const { return iterator::_make(this, this->count()); } + }; + + template<typename interface_t> class array_soft_typed : public array { + public: + typedef service_ptr_t<interface_t> ptr_t; + class iterator { + public: + static iterator _make(const array* arr, size_t index) { + iterator ret; + ret.m_arr = arr; ret.m_index = index; + ret.m_max = arr->count(); + ret.fetch(); + return ret; + } + void operator++() { ++m_index; fetch(); } + bool operator==(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index == other.m_index; } + bool operator!=(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index != other.m_index; } + + ptr_t operator*() const { + PFC_ASSERT(m_ptr.is_valid()); + return m_ptr; + } + private: + void fetch() { + m_ptr.reset(); + while (m_index < m_max) { + if (m_ptr &= m_arr->itemAt(m_index)) break; + ++m_index; + } + } + const array* m_arr; + size_t m_index, m_max; + ptr_t m_ptr; + }; + typedef iterator const_iterator; + iterator begin() const { return iterator::_make(this, 0); } + iterator end() const { return iterator::_make(this, this->count()); } + }; + + class NOVTABLE arrayMutable : public array { + FB2K_MAKE_SERVICE_INTERFACE( arrayMutable, array ); + public: + virtual void remove( pfc::bit_array const & mask ) = 0; + virtual void insert( objRef obj, size_t at ) = 0; + virtual void insertFrom( array::ptr objects, size_t at ) = 0; + virtual void reorder( const size_t * order, size_t count ) = 0; + + virtual void resize( size_t newSize ) = 0; + virtual void setItem( objRef obj, size_t atIndex ) = 0; + + arrayMutable::ptr copy() const; + array::ptr copyConst() const; + + void removeAt( size_t idx ); + void add( objRef obj ) {insert( obj, (size_t)(-1) ) ; } + void addFrom( array::ptr obj ) {insertFrom( obj, (size_t)(-1) ) ; } + static arrayMutable::ptr empty(); + static arrayMutable::ptr arrayWithArray( array::ptr source ); + static arrayMutable::ptr arrayWithObject( objRef source ); + static arrayMutable::ptr arrayWithCapacity(size_t capacity); + }; + + class NOVTABLE string : public service_base { + FB2K_MAKE_SERVICE_INTERFACE( string, service_base ); + public: + virtual const char * c_str() const = 0; + + size_t length() const { return strlen(c_str()); } + bool isEmpty() const { return *c_str() == 0; } + bool equals( const char * other ) const { return strcmp(c_str(), other) == 0; } + bool equals( string::ptr other ) const { return equals(other->c_str()); } + + static string::ptr stringWithString( const char * str ); + static string::ptr stringWithString( string::ptr str ); + static string::ptr stringWithString( const char * str, size_t len ); + static bool equalsNullSafe( string::ptr v1, string::ptr v2 ); + }; + + class NOVTABLE memBlock : public service_base { + FB2K_MAKE_SERVICE_INTERFACE( memBlock, service_base ); + public: + virtual const void * data() const = 0; + virtual size_t size() const = 0; + + const uint8_t * begin() const { return (const uint8_t*) data(); } + const uint8_t * end() const { return begin() + size(); } + + //! Album_art_data compatibility + size_t get_size() { return size(); } + //! Album_art_data compatibility + const void * get_ptr() { return data(); } + + memBlock::ptr copy() const; + + static memBlock::ptr empty(); + static memBlock::ptr blockWithData( const void * inData, size_t inSize); + static memBlock::ptr blockWithBlock( memBlock::ptr block ); + template<typename vec_t> + static memBlock::ptr blockWithVector(const vec_t & vec) { + auto size = vec.size(); + if (size == 0) return empty(); + return blockWithData(&vec[0], size * sizeof(vec[0])); + } + + //! Create an object that takes ownership of this memory, without copying it; will call free() when done. + static memBlock::ptr blockWithDataTakeOwnership(void * inData, size_t inSize); + static memBlock::ptr blockWithData(pfc::mem_block const &); + static memBlock::ptr blockWithData(pfc::mem_block && ); + + //! Determine whether two memBlock objects store the same content. + static bool equals(memBlock const & v1, memBlock const & v2) { + const t_size s = v1.size(); + if (s != v2.size()) return false; + return memcmp(v1.data(), v2.data(),s) == 0; + } + static bool equals(ptr const& v1, ptr const& v2) { + if (v1.is_valid() != v2.is_valid()) return false; + if (v1.is_empty() && v2.is_empty()) return true; + return equals(*v1, *v2); + } + + bool operator==(const memBlock & other) const {return equals(*this,other);} + bool operator!=(const memBlock & other) const {return !equals(*this,other);} + + }; + + class NOVTABLE memBlockMutable : public memBlock { + FB2K_MAKE_SERVICE_INTERFACE( memBlockMutable, memBlock ); + public: + virtual void * dataMutable() = 0; + + //! Resizes preserving content. When expanding, contents of newly allocated area are undefined. + virtual void resize( size_t size ) = 0; + //! Resizes without preserving content. Contents undefined afterwards. + virtual void resizeDiscard( size_t size ) { resize( size ); } + + memBlockMutable::ptr copy() const; + memBlock::ptr copyConst() const; + static memBlockMutable::ptr empty(); + static memBlockMutable::ptr blockWithSize( size_t initSize ); + static memBlockMutable::ptr blockWithData( const void * inData, size_t inSize ); + static memBlockMutable::ptr blockWithBlock( memBlock::ptr block ); + + bool operator==(const memBlockMutable & other) const {return equals(*this,other);} + bool operator!=(const memBlockMutable & other) const {return !equals(*this,other);} + }; + + + //! Asynchronous object return helper. \n + //! If the operation has failed for some reason, receiveObj() will be called with null object. + class objReceiver : public service_base { + FB2K_MAKE_SERVICE_INTERFACE( objReceiver, service_base ); + public: + virtual void receiveObj( objRef obj ) = 0; + }; + + typedef objReceiver::ptr objReceiverRef; + + + typedef ::completion_notify completionNotify; + typedef completionNotify::ptr completionNotifyRef; + typedef array::ptr arrayRef; + typedef arrayMutable::ptr arrayMutableRef; + typedef string::ptr stringRef; + typedef memBlock::ptr memBlockRef; + typedef memBlockMutable::ptr memBlockMutableRef; + + stringRef makeString( const wchar_t * str ); + stringRef makeString( const wchar_t * str, size_t len ); + + inline stringRef makeString( const char * str ) { + return string::stringWithString ( str ); + } + inline stringRef makeString( const char * str, size_t len) { + return string::stringWithString ( str, len ); + } + inline arrayRef makeArray( std::initializer_list<objRef> const & arg ) { + return array::arrayWithObjects( arg ); + } + inline memBlockRef makeMemBlock( const void * data, size_t size ) { + return memBlock::blockWithData( data, size ); + } + + void describe( objRef obj, pfc::string_formatter & output, unsigned indent); + void describeDebug( objRef obj ); + + + typedef std::function< void (objRef) > objReceiverFunc_t; + + objReceiverRef makeObjReceiver( objReceiverFunc_t ); + + template<typename class_t> objReceiverRef makeObjReceiverTyped(std::function< void(service_ptr_t<class_t>) > func) { + return makeObjReceiver([=](objRef obj) { + if (obj.is_empty()) func(nullptr); + else { + service_ptr_t<class_t> temp; temp ^= obj; func(temp); + } + }); + } + + objRef callOnRelease( std::function< void () > ); + objRef callOnReleaseInMainThread( std::function< void () > ); + + arrayRef makeArrayDeferred( std::function< arrayRef () > f ); +} +inline pfc::string_base & operator<<(pfc::string_base & p_fmt, fb2k::stringRef str) { p_fmt.add_string(str->c_str()); return p_fmt; }
