Mercurial > foo_out_sdl
comparison foosdk/sdk/pfc/other.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 "pfc-lite.h" | |
| 2 | |
| 3 #ifdef _MSC_VER | |
| 4 #include <intrin.h> | |
| 5 #include <assert.h> | |
| 6 #endif | |
| 7 #ifndef _MSC_VER | |
| 8 #include <signal.h> | |
| 9 #include <stdlib.h> | |
| 10 #endif | |
| 11 | |
| 12 #if defined(__ANDROID__) | |
| 13 #include <android/log.h> | |
| 14 #endif | |
| 15 | |
| 16 #include <math.h> | |
| 17 | |
| 18 #include "string_base.h" | |
| 19 #include "other.h" | |
| 20 #include "bit_array_impl.h" | |
| 21 #include "order_helper.h" | |
| 22 #include "debug.h" | |
| 23 #include "byte_order.h" | |
| 24 #include "string_conv.h" | |
| 25 #include "memalign.h" | |
| 26 #include "platform-objects.h" | |
| 27 #include "synchro.h" | |
| 28 | |
| 29 #include "pfc-fb2k-hooks.h" | |
| 30 | |
| 31 | |
| 32 namespace pfc { | |
| 33 bool permutation_is_valid(t_size const * order, t_size count) { | |
| 34 bit_array_bittable found(count); | |
| 35 for(t_size walk = 0; walk < count; ++walk) { | |
| 36 const size_t v = order[walk]; | |
| 37 if (v >= count) return false; | |
| 38 if (found[v]) return false; | |
| 39 found.set(v,true); | |
| 40 } | |
| 41 return true; | |
| 42 } | |
| 43 void permutation_validate(t_size const * order, t_size count) { | |
| 44 if (!permutation_is_valid(order,count)) throw exception_invalid_permutation(); | |
| 45 } | |
| 46 | |
| 47 t_size permutation_find_reverse(t_size const * order, t_size count, t_size value) { | |
| 48 if (value >= count) return SIZE_MAX; | |
| 49 for(t_size walk = 0; walk < count; ++walk) { | |
| 50 if (order[walk] == value) return walk; | |
| 51 } | |
| 52 return SIZE_MAX; | |
| 53 } | |
| 54 | |
| 55 void create_move_item_permutation( size_t * order, size_t count, size_t from, size_t to ) { | |
| 56 PFC_ASSERT( from < count ); | |
| 57 PFC_ASSERT( to < count ); | |
| 58 for ( size_t w = 0; w < count; ++w ) { | |
| 59 size_t i = w; | |
| 60 if ( w == to ) i = from; | |
| 61 else if ( w < to && w >= from ) { | |
| 62 ++i; | |
| 63 } else if ( w > to && w <= from ) { | |
| 64 --i; | |
| 65 } | |
| 66 order[w] = i; | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 void create_move_items_permutation(t_size * p_output,t_size p_count,const bit_array & p_selection,int p_delta) { | |
| 71 t_size * const order = p_output; | |
| 72 const t_size count = p_count; | |
| 73 | |
| 74 pfc::array_t<bool> selection; selection.set_size(p_count); | |
| 75 | |
| 76 for(t_size walk = 0; walk < count; ++walk) { | |
| 77 order[walk] = walk; | |
| 78 selection[walk] = p_selection[walk]; | |
| 79 } | |
| 80 | |
| 81 if (p_delta<0) | |
| 82 { | |
| 83 for(;p_delta<0;p_delta++) | |
| 84 { | |
| 85 t_size idx; | |
| 86 for(idx=1;idx<count;idx++) | |
| 87 { | |
| 88 if (selection[idx] && !selection[idx-1]) | |
| 89 { | |
| 90 pfc::swap_t(order[idx],order[idx-1]); | |
| 91 pfc::swap_t(selection[idx],selection[idx-1]); | |
| 92 } | |
| 93 } | |
| 94 } | |
| 95 } | |
| 96 else | |
| 97 { | |
| 98 for(;p_delta>0;p_delta--) | |
| 99 { | |
| 100 t_size idx; | |
| 101 for(idx=count-2;(int)idx>=0;idx--) | |
| 102 { | |
| 103 if (selection[idx] && !selection[idx+1]) | |
| 104 { | |
| 105 pfc::swap_t(order[idx],order[idx+1]); | |
| 106 pfc::swap_t(selection[idx],selection[idx+1]); | |
| 107 } | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 } | |
| 112 bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark ) { | |
| 113 const t_size count = itemCount; | |
| 114 if (insertMark > count) insertMark = count; | |
| 115 { | |
| 116 t_size selBefore = 0; | |
| 117 for(t_size walk = 0; walk < insertMark; ++walk) { | |
| 118 if (maskSelected[walk]) selBefore++; | |
| 119 } | |
| 120 insertMark -= selBefore; | |
| 121 } | |
| 122 { | |
| 123 pfc::array_t<t_size> permutation, selected, nonselected; | |
| 124 | |
| 125 const t_size selcount = maskSelected.calc_count( true, 0, count ); | |
| 126 selected.set_size(selcount); nonselected.set_size(count - selcount); | |
| 127 permutation.set_size(count); | |
| 128 if (insertMark > nonselected.get_size()) insertMark = nonselected.get_size(); | |
| 129 for(t_size walk = 0, swalk = 0, nwalk = 0; walk < count; ++walk) { | |
| 130 if (maskSelected[walk]) { | |
| 131 selected[swalk++] = walk; | |
| 132 } else { | |
| 133 nonselected[nwalk++] = walk; | |
| 134 } | |
| 135 } | |
| 136 for(t_size walk = 0; walk < insertMark; ++walk) { | |
| 137 permutation[walk] = nonselected[walk]; | |
| 138 } | |
| 139 for(t_size walk = 0; walk < selected.get_size(); ++walk) { | |
| 140 permutation[insertMark + walk] = selected[walk]; | |
| 141 } | |
| 142 for(t_size walk = insertMark; walk < nonselected.get_size(); ++walk) { | |
| 143 permutation[selected.get_size() + walk] = nonselected[walk]; | |
| 144 } | |
| 145 for(t_size walk = 0; walk < permutation.get_size(); ++walk) { | |
| 146 if (permutation[walk] != walk) { | |
| 147 memcpy(out, permutation.get_ptr(), count * sizeof(size_t)); | |
| 148 return true; | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 return false; | |
| 153 } | |
| 154 | |
| 155 bool is_identity(size_t const* order, size_t count) { | |
| 156 for (size_t walk = 0; walk < count; ++walk) { | |
| 157 if (order[walk] != walk) return false; | |
| 158 } | |
| 159 return true; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 void order_helper::g_swap(t_size * data,t_size ptr1,t_size ptr2) | |
| 164 { | |
| 165 t_size temp = data[ptr1]; | |
| 166 data[ptr1] = data[ptr2]; | |
| 167 data[ptr2] = temp; | |
| 168 } | |
| 169 | |
| 170 | |
| 171 t_size order_helper::g_find_reverse(const t_size * order,t_size val) | |
| 172 { | |
| 173 t_size prev = val, next = order[val]; | |
| 174 while(next != val) | |
| 175 { | |
| 176 prev = next; | |
| 177 next = order[next]; | |
| 178 } | |
| 179 return prev; | |
| 180 } | |
| 181 | |
| 182 | |
| 183 void order_helper::g_reverse(t_size * order,t_size base,t_size count) | |
| 184 { | |
| 185 t_size max = count>>1; | |
| 186 t_size n; | |
| 187 t_size base2 = base+count-1; | |
| 188 for(n=0;n<max;n++) | |
| 189 g_swap(order,base+n,base2-n); | |
| 190 } | |
| 191 | |
| 192 | |
| 193 [[noreturn]] void pfc::crashImpl() { | |
| 194 #ifdef _WIN32 | |
| 195 for (;;) { __debugbreak(); } | |
| 196 #else | |
| 197 #if defined(__ANDROID__) && PFC_DEBUG | |
| 198 nixSleep(1); | |
| 199 #endif | |
| 200 for ( ;; ) { | |
| 201 *(volatile char*) 0 = 0; | |
| 202 raise(SIGINT); | |
| 203 } | |
| 204 #endif | |
| 205 } | |
| 206 | |
| 207 [[noreturn]] void pfc::crash() { | |
| 208 crashHook(); | |
| 209 } | |
| 210 | |
| 211 | |
| 212 void pfc::byteswap_raw(void * p_buffer,const t_size p_bytes) { | |
| 213 t_uint8 * ptr = (t_uint8*)p_buffer; | |
| 214 t_size n; | |
| 215 for(n=0;n<p_bytes>>1;n++) swap_t(ptr[n],ptr[p_bytes-n-1]); | |
| 216 } | |
| 217 | |
| 218 static pfc::debugLineReceiver * g_debugLineReceivers = nullptr; | |
| 219 | |
| 220 pfc::debugLineReceiver::debugLineReceiver() { | |
| 221 m_chain = g_debugLineReceivers; | |
| 222 g_debugLineReceivers = this; | |
| 223 } | |
| 224 | |
| 225 void pfc::debugLineReceiver::dispatch( const char * msg ) { | |
| 226 for( auto w = g_debugLineReceivers; w != nullptr; w = w->m_chain ) { | |
| 227 w->onLine( msg ); | |
| 228 } | |
| 229 } | |
| 230 namespace pfc { | |
| 231 void appleDebugLog( const char * str ); | |
| 232 } | |
| 233 | |
| 234 void pfc::outputDebugLine(const char * msg) { | |
| 235 debugLineReceiver::dispatch( msg ); | |
| 236 #ifdef _WIN32 | |
| 237 OutputDebugString(pfc::stringcvt::string_os_from_utf8(PFC_string_formatter() << msg << "\n") ); | |
| 238 #elif defined(__ANDROID__) | |
| 239 __android_log_write(ANDROID_LOG_INFO, "Debug", msg); | |
| 240 #elif defined(__APPLE__) | |
| 241 appleDebugLog( msg ); | |
| 242 #else | |
| 243 printf("%s\n", msg); | |
| 244 #endif | |
| 245 } | |
| 246 | |
| 247 void pfc::debugBreak() { | |
| 248 #ifdef _WIN32 | |
| 249 __debugbreak(); | |
| 250 #else | |
| 251 raise(SIGTRAP); | |
| 252 #endif | |
| 253 } | |
| 254 | |
| 255 #if PFC_DEBUG | |
| 256 | |
| 257 #ifdef _WIN32 | |
| 258 void pfc::myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigned _Line) { | |
| 259 if (IsDebuggerPresent()) debugBreak(); | |
| 260 PFC_DEBUGLOG << "PFC_ASSERT failure: " << _Message; | |
| 261 PFC_DEBUGLOG << "PFC_ASSERT location: " << _File << " : " << _Line; | |
| 262 _wassert(_Message,_File,_Line); | |
| 263 } | |
| 264 #else | |
| 265 | |
| 266 void pfc::myassert(const char * _Message, const char *_File, unsigned _Line) | |
| 267 { | |
| 268 PFC_DEBUGLOG << "Assert failure: \"" << _Message << "\" in: " << _File << " line " << _Line; | |
| 269 debugBreak(); | |
| 270 } | |
| 271 #endif | |
| 272 | |
| 273 #endif | |
| 274 | |
| 275 | |
| 276 t_uint64 pfc::pow_int(t_uint64 base, t_uint64 exp) noexcept { | |
| 277 t_uint64 mul = base; | |
| 278 t_uint64 val = 1; | |
| 279 t_uint64 mask = 1; | |
| 280 while(exp != 0) { | |
| 281 if (exp & mask) { | |
| 282 val *= mul; | |
| 283 exp ^= mask; | |
| 284 } | |
| 285 mul = mul * mul; | |
| 286 mask <<= 1; | |
| 287 } | |
| 288 return val; | |
| 289 } | |
| 290 | |
| 291 double pfc::exp_int( const double base, const int expS ) noexcept { | |
| 292 // return pow(base, (double)v); | |
| 293 | |
| 294 bool neg; | |
| 295 unsigned exp; | |
| 296 if (expS < 0) { | |
| 297 neg = true; | |
| 298 exp = (unsigned) -expS; | |
| 299 } else { | |
| 300 neg = false; | |
| 301 exp = (unsigned) expS; | |
| 302 } | |
| 303 double v = 1.0; | |
| 304 if (exp) { | |
| 305 double mul = base; | |
| 306 for(;;) { | |
| 307 if (exp & 1) v *= mul; | |
| 308 exp >>= 1; | |
| 309 if (exp == 0) break; | |
| 310 mul *= mul; | |
| 311 } | |
| 312 } | |
| 313 if (neg) v = 1.0 / v; | |
| 314 return v; | |
| 315 } | |
| 316 | |
| 317 | |
| 318 t_int32 pfc::rint32(double p_val) { return (t_int32)lround(p_val); } | |
| 319 t_int64 pfc::rint64(double p_val) { return (t_int64)llround(p_val); } | |
| 320 | |
| 321 | |
| 322 // mem_block class | |
| 323 namespace pfc { | |
| 324 void mem_block::resize(size_t newSize) { | |
| 325 if (m_size != newSize) { | |
| 326 if (newSize == 0) { | |
| 327 free(m_ptr); m_ptr = nullptr; | |
| 328 } else if (m_size == 0) { | |
| 329 m_ptr = malloc( newSize ); | |
| 330 if (m_ptr == nullptr) throw std::bad_alloc(); | |
| 331 } else { | |
| 332 auto newptr = realloc( m_ptr, newSize ); | |
| 333 if (newptr == nullptr) throw std::bad_alloc(); | |
| 334 m_ptr = newptr; | |
| 335 } | |
| 336 | |
| 337 m_size = newSize; | |
| 338 } | |
| 339 } | |
| 340 void mem_block::clear() noexcept { | |
| 341 free(m_ptr); m_ptr = nullptr; m_size = 0; | |
| 342 } | |
| 343 void mem_block::move( mem_block & other ) noexcept { | |
| 344 clear(); | |
| 345 m_ptr = other.m_ptr; | |
| 346 m_size = other.m_size; | |
| 347 other._clear(); | |
| 348 } | |
| 349 void mem_block::copy( mem_block const & other ) { | |
| 350 const size_t size = other.size(); | |
| 351 resize( size ); | |
| 352 if (size > 0) memcpy(ptr(), other.ptr(), size); | |
| 353 } | |
| 354 | |
| 355 // aligned alloc | |
| 356 void alignedAlloc( void* & m_ptr, size_t & m_size, size_t s, size_t alignBytes) { | |
| 357 if (s == m_size) { | |
| 358 // nothing to do | |
| 359 } else if (s == 0) { | |
| 360 alignedFree(m_ptr); | |
| 361 m_ptr = NULL; | |
| 362 } else { | |
| 363 void * ptr; | |
| 364 #ifdef _MSC_VER | |
| 365 if (m_ptr == NULL) ptr = _aligned_malloc(s, alignBytes); | |
| 366 else ptr = _aligned_realloc(m_ptr, s, alignBytes); | |
| 367 if ( ptr == NULL ) throw std::bad_alloc(); | |
| 368 #else | |
| 369 #ifdef __ANDROID__ | |
| 370 if ((ptr = memalign( alignBytes, s )) == NULL) throw std::bad_alloc(); | |
| 371 #else | |
| 372 if (posix_memalign( &ptr, alignBytes, s ) < 0) throw std::bad_alloc(); | |
| 373 #endif | |
| 374 if (m_ptr != NULL) { | |
| 375 memcpy( ptr, m_ptr, min_t<size_t>( m_size, s ) ); | |
| 376 alignedFree( m_ptr ); | |
| 377 } | |
| 378 #endif | |
| 379 m_ptr = ptr; | |
| 380 } | |
| 381 m_size = s; | |
| 382 } | |
| 383 | |
| 384 void* alignedAlloc( size_t s, size_t alignBytes ) { | |
| 385 void * ptr; | |
| 386 #ifdef _MSC_VER | |
| 387 ptr = _aligned_malloc(s, alignBytes); | |
| 388 if (ptr == nullptr) throw std::bad_alloc(); | |
| 389 #else | |
| 390 #ifdef __ANDROID__ | |
| 391 if ((ptr = memalign( alignBytes, s )) == NULL) throw std::bad_alloc(); | |
| 392 #else | |
| 393 if (posix_memalign( &ptr, alignBytes, s ) < 0) throw std::bad_alloc(); | |
| 394 #endif | |
| 395 #endif | |
| 396 return ptr; | |
| 397 } | |
| 398 | |
| 399 void alignedFree( void * ptr ) { | |
| 400 #ifdef _MSC_VER | |
| 401 _aligned_free(ptr); | |
| 402 #else | |
| 403 free(ptr); | |
| 404 #endif | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 | |
| 409 #include "once.h" | |
| 410 | |
| 411 namespace pfc { | |
| 412 #if PFC_CUSTOM_ONCE_FLAG | |
| 413 static pfc::once_flag_lite g_onceGuardGuard; | |
| 414 static mutex * g_onceGuard; | |
| 415 | |
| 416 static mutex & onceGuard() { | |
| 417 call_once(g_onceGuardGuard, [] { | |
| 418 g_onceGuard = new mutex(); | |
| 419 } ); | |
| 420 return * g_onceGuard; | |
| 421 } | |
| 422 | |
| 423 void call_once( once_flag & flag, std::function<void () > work ) { | |
| 424 | |
| 425 if ( flag.done ) return; | |
| 426 | |
| 427 mutex & guard = onceGuard(); | |
| 428 for ( ;; ) { | |
| 429 std::shared_ptr<pfc::event> waitFor; | |
| 430 { | |
| 431 insync(guard); | |
| 432 if ( flag.done ) { | |
| 433 PFC_ASSERT( ! flag.inProgress ); | |
| 434 return; | |
| 435 } | |
| 436 if ( flag.inProgress ) { | |
| 437 if ( ! flag.waitFor ) flag.waitFor = std::make_shared< event > (); | |
| 438 waitFor = flag.waitFor; | |
| 439 } else { | |
| 440 flag.inProgress = true; | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 if ( waitFor ) { | |
| 445 waitFor->wait_for( -1 ); | |
| 446 continue; | |
| 447 } | |
| 448 | |
| 449 try { | |
| 450 work(); | |
| 451 } catch(...) { | |
| 452 insync( guard ); | |
| 453 PFC_ASSERT( ! flag.done ); | |
| 454 PFC_ASSERT( flag.inProgress ); | |
| 455 flag.inProgress = false; | |
| 456 if ( flag.waitFor ) { | |
| 457 flag.waitFor->set_state( true ); | |
| 458 flag.waitFor.reset(); | |
| 459 } | |
| 460 throw; | |
| 461 } | |
| 462 | |
| 463 // succeeded | |
| 464 insync( guard ); | |
| 465 PFC_ASSERT( ! flag.done ); | |
| 466 PFC_ASSERT( flag.inProgress ); | |
| 467 flag.inProgress = false; | |
| 468 flag.done = true; | |
| 469 if ( flag.waitFor ) { | |
| 470 flag.waitFor->set_state( true ); | |
| 471 flag.waitFor.reset(); | |
| 472 } | |
| 473 return; | |
| 474 } | |
| 475 } | |
| 476 #endif | |
| 477 void call_once( once_flag_lite & flag, std::function<void ()> work ) { | |
| 478 for ( ;; ) { | |
| 479 if ( flag.done ) return; | |
| 480 if (! threadSafeInt::exchangeHere(flag.guard, 1)) { | |
| 481 try { | |
| 482 work(); | |
| 483 } catch(...) { | |
| 484 flag.guard = 0; | |
| 485 throw; | |
| 486 } | |
| 487 flag.done = true; | |
| 488 return; | |
| 489 } | |
| 490 yield(); | |
| 491 } | |
| 492 } | |
| 493 | |
| 494 | |
| 495 #ifdef PFC_SET_THREAD_DESCRIPTION_EXTERNAL | |
| 496 static std::function<void (const char*)> g_setCurrentThreadDescription; | |
| 497 void initSetCurrentThreadDescription( std::function<void (const char*)> f ) { g_setCurrentThreadDescription = f; } | |
| 498 #endif | |
| 499 | |
| 500 void setCurrentThreadDescription( const char * msg ) { | |
| 501 #ifdef __APPLE__ | |
| 502 appleSetThreadDescription( msg ); | |
| 503 #endif | |
| 504 | |
| 505 #ifdef PFC_WINDOWS_DESKTOP_APP | |
| 506 winSetThreadDescription(GetCurrentThread(), pfc::stringcvt::string_wide_from_utf8( msg ) );; | |
| 507 #endif | |
| 508 #ifdef PFC_SET_THREAD_DESCRIPTION_EXTERNAL | |
| 509 if (g_setCurrentThreadDescription) g_setCurrentThreadDescription(msg); | |
| 510 #endif | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 |
