Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/SDK/commonObjects.cpp @ 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 #include "foobar2000-sdk-pch.h" | |
| 2 | |
| 3 #include <pfc/sort.h> | |
| 4 #include <pfc/bit_array_impl.h> | |
| 5 #include <pfc/string_conv.h> | |
| 6 #ifdef FOOBAR2000_MOBILE | |
| 7 #include "browseTree.h" | |
| 8 #endif | |
| 9 #include <mutex> | |
| 10 | |
| 11 namespace { | |
| 12 class arrayImpl : public fb2k::array { | |
| 13 public: | |
| 14 arrayImpl() {} | |
| 15 arrayImpl(std::initializer_list<fb2k::objRef> const& arg) { | |
| 16 m_content.set_size_discard(arg.size()); | |
| 17 size_t walk = 0; | |
| 18 for (auto& obj : arg) m_content[walk++] = obj; | |
| 19 } | |
| 20 arrayImpl( array::ptr in ) { | |
| 21 const size_t count = in->count(); | |
| 22 m_content.set_size_discard( count ); | |
| 23 for(size_t w = 0; w < count; ++w) m_content[w] = in->itemAt(w); | |
| 24 } | |
| 25 arrayImpl( array::ptr in, size_t const * order, size_t count ) { | |
| 26 if (count != in->count()) uBugCheck(); | |
| 27 m_content.set_size_discard(count); | |
| 28 for(size_t w = 0; w < count; ++w) m_content[w] = in->itemAt( order[w] ); | |
| 29 } | |
| 30 arrayImpl( fb2k::objRef in ) { | |
| 31 m_content.set_size_discard( 1 ) ; | |
| 32 m_content[0] = in; | |
| 33 } | |
| 34 arrayImpl( fb2k::objRef const * in, size_t inCount) { | |
| 35 m_content.set_data_fromptr( in, inCount ); | |
| 36 } | |
| 37 size_t count() const { return m_content.get_size(); } | |
| 38 service_ptr itemAt(size_t idx) const { return m_content[idx]; } | |
| 39 | |
| 40 private: | |
| 41 pfc::array_staticsize_t< service_ptr > m_content; | |
| 42 }; | |
| 43 class arrayMutableImpl : public fb2k::arrayMutable { | |
| 44 public: | |
| 45 arrayMutableImpl() {} | |
| 46 arrayMutableImpl( array::ptr in ) { | |
| 47 const size_t count = in->count(); | |
| 48 m_content.set_size_discard( count ); | |
| 49 for(size_t w = 0; w < count; ++w) { | |
| 50 m_content[w] = in->itemAt( w ); | |
| 51 } | |
| 52 } | |
| 53 arrayMutableImpl( fb2k::objRef in ) { | |
| 54 m_content.set_size_discard( 1 ); | |
| 55 m_content[0] = in; | |
| 56 } | |
| 57 size_t count() const { return m_content.get_size(); } | |
| 58 fb2k::objRef itemAt( size_t idx ) const { return m_content[idx]; } | |
| 59 void remove( pfc::bit_array const & mask ) { | |
| 60 pfc::remove_mask_t( m_content, mask ); | |
| 61 } | |
| 62 void insert( fb2k::objRef obj, size_t at ) { | |
| 63 pfc::insert_t( m_content, obj, at ); | |
| 64 } | |
| 65 void insertFrom( array::ptr objects, size_t at ) { | |
| 66 if (objects.get_ptr() == this) { | |
| 67 objects = arrayWithArray( objects ); | |
| 68 } | |
| 69 pfc::insert_multi_t( m_content, *objects, objects->count(), at ); | |
| 70 } | |
| 71 void reorder( const size_t * order, size_t count ) { | |
| 72 if (count != m_content.get_size()) uBugCheck(); | |
| 73 pfc::reorder_t( m_content, order, count ); | |
| 74 } | |
| 75 | |
| 76 void resize( size_t newSize ) { | |
| 77 m_content.set_size( newSize ); | |
| 78 } | |
| 79 void setItem( fb2k::objRef obj, size_t atIndex ) { | |
| 80 if (atIndex > m_content.get_size()) uBugCheck(); | |
| 81 m_content[atIndex] = obj; | |
| 82 } | |
| 83 void prealloc(size_t capacity) { | |
| 84 m_content.prealloc(capacity); | |
| 85 } | |
| 86 private: | |
| 87 pfc::array_t< fb2k::objRef, pfc::alloc_fast > m_content; | |
| 88 }; | |
| 89 | |
| 90 class stringImpl : public fb2k::string { | |
| 91 public: | |
| 92 stringImpl( const wchar_t * str, size_t len = pfc_infinite ) { | |
| 93 size_t n = pfc::stringcvt::estimate_wide_to_utf8( str, len ); | |
| 94 m_str = (char*) malloc( n ); | |
| 95 pfc::stringcvt::convert_wide_to_utf8( m_str, n, str, len ); | |
| 96 } | |
| 97 stringImpl( const char * str ) { | |
| 98 m_str = pfc::strDup(str); | |
| 99 if (m_str == nullptr) throw std::bad_alloc(); | |
| 100 } | |
| 101 stringImpl( const char * str, size_t len ) { | |
| 102 len = pfc::strlen_max( str, len ); | |
| 103 m_str = (char*)malloc( len + 1 ); | |
| 104 if (m_str == nullptr) throw std::bad_alloc(); | |
| 105 memcpy (m_str, str, len ); | |
| 106 m_str[len] = 0; | |
| 107 } | |
| 108 | |
| 109 ~stringImpl() { | |
| 110 free(m_str); | |
| 111 } | |
| 112 const char * c_str() const {return m_str;} | |
| 113 private: | |
| 114 char * m_str; | |
| 115 }; | |
| 116 | |
| 117 | |
| 118 | |
| 119 class memBlockImpl : public fb2k::memBlock { | |
| 120 public: | |
| 121 memBlockImpl( const void * inData, size_t inDataSize ) { | |
| 122 m_data.set_data_fromptr( (const uint8_t*) inData, inDataSize ); | |
| 123 } | |
| 124 const void * data() const { | |
| 125 return m_data.get_ptr(); | |
| 126 } | |
| 127 size_t size() const { | |
| 128 return m_data.get_size(); | |
| 129 } | |
| 130 private: | |
| 131 pfc::array_staticsize_t< uint8_t > m_data; | |
| 132 }; | |
| 133 | |
| 134 class memBlockImpl_takeOwnership : public fb2k::memBlock { | |
| 135 public: | |
| 136 memBlockImpl_takeOwnership(void * data, size_t size) : m_data(data), m_size(size) {} | |
| 137 ~memBlockImpl_takeOwnership() { free(m_data); } | |
| 138 const void * data() const { return m_data; } | |
| 139 size_t size() const { return m_size; } | |
| 140 private: | |
| 141 void * const m_data; | |
| 142 const size_t m_size; | |
| 143 }; | |
| 144 | |
| 145 class memBlockMutableImpl : public fb2k::memBlockMutable { | |
| 146 public: | |
| 147 memBlockMutableImpl( size_t initSize ) { m_data.set_size_discard( initSize ); } | |
| 148 memBlockMutableImpl( const void * inData, size_t inSize) { | |
| 149 m_data.set_data_fromptr( (const uint8_t*) inData, inSize ); | |
| 150 } | |
| 151 memBlockMutableImpl() {} | |
| 152 | |
| 153 const void * data() const { return m_data.get_ptr(); } | |
| 154 void * dataMutable() { return m_data.get_ptr(); } | |
| 155 | |
| 156 size_t size() const { return m_data.get_size(); } | |
| 157 void resize( size_t size ) { m_data.set_size( size ); } | |
| 158 void resizeDiscard( size_t size ) { m_data.set_size_discard( size ); } | |
| 159 | |
| 160 private: | |
| 161 pfc::array_t< uint8_t > m_data; | |
| 162 }; | |
| 163 } | |
| 164 | |
| 165 namespace fb2k { | |
| 166 FOOGUIDDECL const GUID array::class_guid = { 0x3f2c5273, 0x6cea, 0x427d, { 0x8c, 0x74, 0x34, 0x79, 0xc7, 0x22, 0x6a, 0x1 } }; | |
| 167 FOOGUIDDECL const GUID arrayMutable::class_guid = { 0x142709d1, 0x9cef, 0x42c4, { 0xb5, 0x63, 0xbc, 0x3a, 0xee, 0x8, 0xdc, 0xe3 } }; | |
| 168 FOOGUIDDECL const GUID string::class_guid = { 0xb3572de3, 0xdc77, 0x4494, { 0xa3, 0x90, 0xb1, 0xff, 0xd9, 0x17, 0x38, 0x77 } }; | |
| 169 // ! Old GUID of album_art_data ! | |
| 170 FOOGUIDDECL const GUID memBlock::class_guid = { 0x9ddce05c, 0xaa3f, 0x4565, { 0xb3, 0x3a, 0xbd, 0x6a, 0xdc, 0xdd, 0x90, 0x37 } }; | |
| 171 FOOGUIDDECL const GUID memBlockMutable::class_guid = { 0x481ab64c, 0xa28, 0x435b, { 0x85, 0xdc, 0x9e, 0x20, 0xfe, 0x92, 0x15, 0x61 } }; | |
| 172 FOOGUIDDECL const GUID objReceiver::class_guid = { 0x1b60d9fa, 0xcb9d, 0x45a4, { 0x90, 0x4e, 0xa, 0xa8, 0xaa, 0xe7, 0x99, 0x7c } }; | |
| 173 | |
| 174 array::ptr array::arrayReordered( size_t const * order, size_t count ) { | |
| 175 return new service_impl_t< arrayImpl > ( this, order, count ); | |
| 176 } | |
| 177 array::ptr array::copy() const { | |
| 178 return arrayWithArray( const_cast<array*>( this ) ); | |
| 179 } | |
| 180 | |
| 181 array::ptr array::empty() { | |
| 182 return new service_impl_t< arrayImpl >(); | |
| 183 } | |
| 184 | |
| 185 array::ptr array::arrayWithArray( array::ptr source ) { | |
| 186 return new service_impl_t< arrayImpl > ( source ); | |
| 187 } | |
| 188 array::ptr array::arrayWithObject( objRef source ) { | |
| 189 return new service_impl_t< arrayImpl > ( source ); | |
| 190 } | |
| 191 array::ptr array::arrayWithObjects( objRef const * source, size_t count ) { | |
| 192 return new service_impl_t<arrayImpl>( source, count ); | |
| 193 } | |
| 194 array::ptr array::arrayWithObjects(std::initializer_list< objRef > const& arg) { | |
| 195 return new service_impl_t<arrayImpl>(arg); | |
| 196 } | |
| 197 arrayMutable::ptr arrayMutable::arrayWithCapacity(size_t capacity) { | |
| 198 auto ret = fb2k::service_new< arrayMutableImpl >(); | |
| 199 ret->prealloc(capacity); | |
| 200 return ret; | |
| 201 } | |
| 202 arrayMutable::ptr arrayMutable::empty() { | |
| 203 return new service_impl_t< arrayMutableImpl > (); | |
| 204 } | |
| 205 arrayMutable::ptr arrayMutable::arrayWithArray( array::ptr source ) { | |
| 206 return new service_impl_t< arrayMutableImpl > ( source ); | |
| 207 } | |
| 208 arrayMutable::ptr arrayMutable::arrayWithObject( objRef source ) { | |
| 209 return new service_impl_t< arrayMutableImpl > ( source ); | |
| 210 } | |
| 211 arrayMutable::ptr arrayMutable::copy() const { | |
| 212 return arrayWithArray( const_cast<arrayMutable*>(this) ); | |
| 213 } | |
| 214 array::ptr array::makeConst() const { | |
| 215 arrayMutableRef mut; | |
| 216 if (mut &= const_cast<array*>(this)) return mut->copyConst(); | |
| 217 return const_cast<array*>(this); | |
| 218 } | |
| 219 array::ptr arrayMutable::copyConst() const { | |
| 220 return array::arrayWithArray( const_cast<arrayMutable*>(this) ); | |
| 221 } | |
| 222 | |
| 223 string::ptr string::stringWithString( const char * str ) { | |
| 224 return new service_impl_t< stringImpl > (str); | |
| 225 } | |
| 226 string::ptr string::stringWithString( const char * str, size_t len ) { | |
| 227 return new service_impl_t< stringImpl > (str, len); | |
| 228 } | |
| 229 string::ptr string::stringWithString( string::ptr str ) { | |
| 230 return new service_impl_t< stringImpl > (str->c_str() ); | |
| 231 } | |
| 232 bool string::equalsNullSafe( string::ptr v1, string::ptr v2 ) { | |
| 233 if (v1.is_empty() && v2.is_empty()) return true; | |
| 234 if (v1.is_empty() || v2.is_empty()) return false; | |
| 235 return v1->equals( v2 ); | |
| 236 } | |
| 237 | |
| 238 memBlock::ptr memBlock::empty() { | |
| 239 return blockWithData(NULL, 0); | |
| 240 } | |
| 241 memBlock::ptr memBlock::blockWithDataTakeOwnership(void * inData, size_t inSize) { | |
| 242 return new service_impl_t< memBlockImpl_takeOwnership >(inData, inSize); | |
| 243 } | |
| 244 memBlock::ptr memBlock::blockWithData( const void * inData, size_t inSize) { | |
| 245 return new service_impl_t< memBlockImpl > ( inData, inSize ); | |
| 246 } | |
| 247 memBlock::ptr memBlock::blockWithData(pfc::mem_block const& b) { | |
| 248 return blockWithData(b.ptr(), b.size()); | |
| 249 } | |
| 250 memBlock::ptr memBlock::blockWithData(pfc::mem_block&& b) { | |
| 251 auto ret = blockWithDataTakeOwnership(b.ptr(), b.size()); | |
| 252 b.detach(); | |
| 253 return ret; | |
| 254 } | |
| 255 memBlock::ptr memBlock::copy() const { | |
| 256 return blockWithBlock( const_cast<memBlock*>( this ) ); | |
| 257 } | |
| 258 | |
| 259 memBlockMutable::ptr memBlockMutable::copy() const { | |
| 260 return blockWithBlock( const_cast<memBlockMutable*>( this ) ); | |
| 261 } | |
| 262 memBlock::ptr memBlockMutable::copyConst() const { | |
| 263 return memBlock::blockWithBlock( const_cast<memBlockMutable*>(this) ); | |
| 264 } | |
| 265 | |
| 266 memBlockMutableRef memBlockMutable::empty() { | |
| 267 return new service_impl_t< memBlockMutableImpl >; | |
| 268 } | |
| 269 memBlockMutableRef memBlockMutable::blockWithSize(size_t initSize) { | |
| 270 return new service_impl_t< memBlockMutableImpl >( initSize ); | |
| 271 } | |
| 272 | |
| 273 memBlockRef memBlock::blockWithBlock(memBlock::ptr block) { | |
| 274 return blockWithData( block->data(), block->size() ); | |
| 275 } | |
| 276 memBlockMutableRef memBlockMutable::blockWithData( const void * inData, size_t inSize ) { | |
| 277 return new service_impl_t< memBlockMutableImpl >( inData, inSize ); | |
| 278 } | |
| 279 | |
| 280 memBlockMutableRef memBlockMutable::blockWithBlock(memBlock::ptr block) { | |
| 281 return blockWithData( block->data(), block->size() ); | |
| 282 } | |
| 283 | |
| 284 void describe( objRef obj, pfc::string_formatter & output, unsigned indent) { | |
| 285 output.add_chars( ' ', indent * 2 ); | |
| 286 { | |
| 287 stringRef str; | |
| 288 if (obj->cast(str)) { | |
| 289 output << "string: " << str->c_str() << "\n"; | |
| 290 return; | |
| 291 } | |
| 292 } | |
| 293 { | |
| 294 arrayRef arr; | |
| 295 if (obj->cast(arr)) { | |
| 296 arrayMutableRef mut; | |
| 297 if (obj->cast(mut)) { | |
| 298 output << "arrayMutable"; | |
| 299 } else { | |
| 300 output << "array"; | |
| 301 } | |
| 302 const size_t count = arr->count(); | |
| 303 output << " (" << count << " items):\n"; | |
| 304 for(size_t w = 0; w < count; ++w) { | |
| 305 describe( arr->itemAt(w), output, indent + 1); | |
| 306 } | |
| 307 return; | |
| 308 } | |
| 309 } | |
| 310 { | |
| 311 memBlockRef block; | |
| 312 if (obj->cast(block)) { | |
| 313 memBlockMutableRef mut; | |
| 314 if (obj->cast(mut)) { | |
| 315 output << "memBlockMutable"; | |
| 316 } else { | |
| 317 output << "memBlock"; | |
| 318 } | |
| 319 output << " (" << block->size() << " bytes)\n"; | |
| 320 return; | |
| 321 } | |
| 322 } | |
| 323 #ifdef FOOBAR2000_MOBILE | |
| 324 { | |
| 325 browseTreeItem::ptr item; | |
| 326 if (obj->cast(item)) { | |
| 327 output << "browseTreeItem\n"; | |
| 328 return; | |
| 329 } | |
| 330 } | |
| 331 #endif | |
| 332 | |
| 333 output << "[unknown]\n"; | |
| 334 } | |
| 335 | |
| 336 void describeDebug( objRef obj ) { | |
| 337 console::formatter temp; | |
| 338 describe( obj, temp, 0 ); | |
| 339 } | |
| 340 | |
| 341 void arrayMutable::removeAt( size_t idx ) { | |
| 342 remove(pfc::bit_array_one (idx) ) ; | |
| 343 } | |
| 344 | |
| 345 stringRef makeString( const wchar_t * str ) { | |
| 346 return new service_impl_t<stringImpl>(str); | |
| 347 } | |
| 348 | |
| 349 stringRef makeString( const wchar_t * str, size_t len ) { | |
| 350 return new service_impl_t<stringImpl>(str, len); | |
| 351 } | |
| 352 } | |
| 353 | |
| 354 namespace { | |
| 355 using namespace fb2k; | |
| 356 class objReceiverImpl : public objReceiver { | |
| 357 public: | |
| 358 objReceiverImpl( const objReceiverFunc_t & f ) : m_func(f) {} | |
| 359 void receiveObj(objRef obj) { | |
| 360 m_func(obj); | |
| 361 } | |
| 362 | |
| 363 objReceiverFunc_t m_func; | |
| 364 }; | |
| 365 | |
| 366 class callOnReleaseImpl : public service_base { | |
| 367 public: | |
| 368 callOnReleaseImpl( std::function<void () > f_) : f(f_) {} | |
| 369 std::function<void ()> f; | |
| 370 | |
| 371 ~callOnReleaseImpl () { | |
| 372 try { | |
| 373 f(); | |
| 374 } catch(...) {} | |
| 375 } | |
| 376 }; | |
| 377 | |
| 378 class arrayDeferred : public array { | |
| 379 public: | |
| 380 arrayDeferred( std::function<arrayRef () > f ) : m_func(f) {} | |
| 381 size_t count() const { | |
| 382 init(); | |
| 383 return m_chain->count(); | |
| 384 } | |
| 385 objRef itemAt( size_t index ) const { | |
| 386 init(); | |
| 387 return m_chain->itemAt( index ); | |
| 388 } | |
| 389 private: | |
| 390 mutable std::once_flag m_once; | |
| 391 mutable std::function< arrayRef () > m_func; | |
| 392 mutable arrayRef m_chain; | |
| 393 void init() const { | |
| 394 std::call_once( m_once, [this] { | |
| 395 m_chain = m_func(); | |
| 396 } ); | |
| 397 } | |
| 398 }; | |
| 399 } | |
| 400 | |
| 401 namespace fb2k { | |
| 402 | |
| 403 objReceiverRef makeObjReceiver( objReceiverFunc_t f ) { | |
| 404 return new service_impl_t< objReceiverImpl > ( f ); | |
| 405 } | |
| 406 | |
| 407 objRef callOnRelease( std::function< void () > f) { | |
| 408 return new service_impl_t< callOnReleaseImpl > (f); | |
| 409 } | |
| 410 objRef callOnReleaseInMainThread( std::function< void () > f) { | |
| 411 return callOnRelease( [f] { | |
| 412 fb2k::inMainThread2( f ); | |
| 413 }); | |
| 414 } | |
| 415 arrayRef makeArrayDeferred( std::function< arrayRef () > f ) { | |
| 416 return new service_impl_t<arrayDeferred> ( f ); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 namespace fb2k { | |
| 421 objRef array::firstItem() const { | |
| 422 size_t n = this->count(); | |
| 423 if ( n == 0 ) return nullptr; | |
| 424 return this->itemAt( 0 ); | |
| 425 } | |
| 426 | |
| 427 objRef array::lastItem() const { | |
| 428 size_t n = this->count(); | |
| 429 if ( n == 0 ) return nullptr; | |
| 430 return this->itemAt( n - 1 ); | |
| 431 } | |
| 432 | |
| 433 size_t array::indexOfItem(objRef item) { | |
| 434 const size_t m = this->count(); | |
| 435 for( size_t n = 0; n < m; ++n ) { | |
| 436 auto obj = this->itemAt( n ); | |
| 437 if ( obj == item ) return n; | |
| 438 } | |
| 439 return SIZE_MAX; | |
| 440 } | |
| 441 | |
| 442 array::ptr array::subset( pfc::bit_array const & mask ) const { | |
| 443 auto out = arrayMutable::empty(); | |
| 444 mask.walk( this->size(), [=] ( size_t w ) { | |
| 445 out->add( this->itemAt( w ) ); | |
| 446 } ); | |
| 447 return out->makeConst(); | |
| 448 } | |
| 449 | |
| 450 array::ptr array::subsetExcluding(const pfc::bit_array & mask) const { | |
| 451 return subset(pfc::bit_array_not(mask) ); | |
| 452 } | |
| 453 array::ptr array::subsetExcludingSingle( size_t index ) const { | |
| 454 return subsetExcluding(pfc::bit_array_one(index ) ); | |
| 455 } | |
| 456 } |
