Mercurial > foo_out_sdl
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/pfc/other.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,514 @@ +#include "pfc-lite.h" + +#ifdef _MSC_VER +#include <intrin.h> +#include <assert.h> +#endif +#ifndef _MSC_VER +#include <signal.h> +#include <stdlib.h> +#endif + +#if defined(__ANDROID__) +#include <android/log.h> +#endif + +#include <math.h> + +#include "string_base.h" +#include "other.h" +#include "bit_array_impl.h" +#include "order_helper.h" +#include "debug.h" +#include "byte_order.h" +#include "string_conv.h" +#include "memalign.h" +#include "platform-objects.h" +#include "synchro.h" + +#include "pfc-fb2k-hooks.h" + + +namespace pfc { + bool permutation_is_valid(t_size const * order, t_size count) { + bit_array_bittable found(count); + for(t_size walk = 0; walk < count; ++walk) { + const size_t v = order[walk]; + if (v >= count) return false; + if (found[v]) return false; + found.set(v,true); + } + return true; + } + void permutation_validate(t_size const * order, t_size count) { + if (!permutation_is_valid(order,count)) throw exception_invalid_permutation(); + } + + t_size permutation_find_reverse(t_size const * order, t_size count, t_size value) { + if (value >= count) return SIZE_MAX; + for(t_size walk = 0; walk < count; ++walk) { + if (order[walk] == value) return walk; + } + return SIZE_MAX; + } + + void create_move_item_permutation( size_t * order, size_t count, size_t from, size_t to ) { + PFC_ASSERT( from < count ); + PFC_ASSERT( to < count ); + for ( size_t w = 0; w < count; ++w ) { + size_t i = w; + if ( w == to ) i = from; + else if ( w < to && w >= from ) { + ++i; + } else if ( w > to && w <= from ) { + --i; + } + order[w] = i; + } + } + + void create_move_items_permutation(t_size * p_output,t_size p_count,const bit_array & p_selection,int p_delta) { + t_size * const order = p_output; + const t_size count = p_count; + + pfc::array_t<bool> selection; selection.set_size(p_count); + + for(t_size walk = 0; walk < count; ++walk) { + order[walk] = walk; + selection[walk] = p_selection[walk]; + } + + if (p_delta<0) + { + for(;p_delta<0;p_delta++) + { + t_size idx; + for(idx=1;idx<count;idx++) + { + if (selection[idx] && !selection[idx-1]) + { + pfc::swap_t(order[idx],order[idx-1]); + pfc::swap_t(selection[idx],selection[idx-1]); + } + } + } + } + else + { + for(;p_delta>0;p_delta--) + { + t_size idx; + for(idx=count-2;(int)idx>=0;idx--) + { + if (selection[idx] && !selection[idx+1]) + { + pfc::swap_t(order[idx],order[idx+1]); + pfc::swap_t(selection[idx],selection[idx+1]); + } + } + } + } + } + bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark ) { + const t_size count = itemCount; + if (insertMark > count) insertMark = count; + { + t_size selBefore = 0; + for(t_size walk = 0; walk < insertMark; ++walk) { + if (maskSelected[walk]) selBefore++; + } + insertMark -= selBefore; + } + { + pfc::array_t<t_size> permutation, selected, nonselected; + + const t_size selcount = maskSelected.calc_count( true, 0, count ); + selected.set_size(selcount); nonselected.set_size(count - selcount); + permutation.set_size(count); + if (insertMark > nonselected.get_size()) insertMark = nonselected.get_size(); + for(t_size walk = 0, swalk = 0, nwalk = 0; walk < count; ++walk) { + if (maskSelected[walk]) { + selected[swalk++] = walk; + } else { + nonselected[nwalk++] = walk; + } + } + for(t_size walk = 0; walk < insertMark; ++walk) { + permutation[walk] = nonselected[walk]; + } + for(t_size walk = 0; walk < selected.get_size(); ++walk) { + permutation[insertMark + walk] = selected[walk]; + } + for(t_size walk = insertMark; walk < nonselected.get_size(); ++walk) { + permutation[selected.get_size() + walk] = nonselected[walk]; + } + for(t_size walk = 0; walk < permutation.get_size(); ++walk) { + if (permutation[walk] != walk) { + memcpy(out, permutation.get_ptr(), count * sizeof(size_t)); + return true; + } + } + } + return false; + } + + bool is_identity(size_t const* order, size_t count) { + for (size_t walk = 0; walk < count; ++walk) { + if (order[walk] != walk) return false; + } + return true; + } +} + +void order_helper::g_swap(t_size * data,t_size ptr1,t_size ptr2) +{ + t_size temp = data[ptr1]; + data[ptr1] = data[ptr2]; + data[ptr2] = temp; +} + + +t_size order_helper::g_find_reverse(const t_size * order,t_size val) +{ + t_size prev = val, next = order[val]; + while(next != val) + { + prev = next; + next = order[next]; + } + return prev; +} + + +void order_helper::g_reverse(t_size * order,t_size base,t_size count) +{ + t_size max = count>>1; + t_size n; + t_size base2 = base+count-1; + for(n=0;n<max;n++) + g_swap(order,base+n,base2-n); +} + + +[[noreturn]] void pfc::crashImpl() { +#ifdef _WIN32 + for (;;) { __debugbreak(); } +#else +#if defined(__ANDROID__) && PFC_DEBUG + nixSleep(1); +#endif + for ( ;; ) { + *(volatile char*) 0 = 0; + raise(SIGINT); + } +#endif +} + +[[noreturn]] void pfc::crash() { + crashHook(); +} + + +void pfc::byteswap_raw(void * p_buffer,const t_size p_bytes) { + t_uint8 * ptr = (t_uint8*)p_buffer; + t_size n; + for(n=0;n<p_bytes>>1;n++) swap_t(ptr[n],ptr[p_bytes-n-1]); +} + +static pfc::debugLineReceiver * g_debugLineReceivers = nullptr; + +pfc::debugLineReceiver::debugLineReceiver() { + m_chain = g_debugLineReceivers; + g_debugLineReceivers = this; +} + +void pfc::debugLineReceiver::dispatch( const char * msg ) { + for( auto w = g_debugLineReceivers; w != nullptr; w = w->m_chain ) { + w->onLine( msg ); + } +} +namespace pfc { + void appleDebugLog( const char * str ); +} + +void pfc::outputDebugLine(const char * msg) { + debugLineReceiver::dispatch( msg ); +#ifdef _WIN32 + OutputDebugString(pfc::stringcvt::string_os_from_utf8(PFC_string_formatter() << msg << "\n") ); +#elif defined(__ANDROID__) + __android_log_write(ANDROID_LOG_INFO, "Debug", msg); +#elif defined(__APPLE__) + appleDebugLog( msg ); +#else + printf("%s\n", msg); +#endif +} + +void pfc::debugBreak() { +#ifdef _WIN32 + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} + +#if PFC_DEBUG + +#ifdef _WIN32 +void pfc::myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigned _Line) { + if (IsDebuggerPresent()) debugBreak(); + PFC_DEBUGLOG << "PFC_ASSERT failure: " << _Message; + PFC_DEBUGLOG << "PFC_ASSERT location: " << _File << " : " << _Line; + _wassert(_Message,_File,_Line); +} +#else + +void pfc::myassert(const char * _Message, const char *_File, unsigned _Line) +{ + PFC_DEBUGLOG << "Assert failure: \"" << _Message << "\" in: " << _File << " line " << _Line; + debugBreak(); +} +#endif + +#endif + + +t_uint64 pfc::pow_int(t_uint64 base, t_uint64 exp) noexcept { + t_uint64 mul = base; + t_uint64 val = 1; + t_uint64 mask = 1; + while(exp != 0) { + if (exp & mask) { + val *= mul; + exp ^= mask; + } + mul = mul * mul; + mask <<= 1; + } + return val; +} + +double pfc::exp_int( const double base, const int expS ) noexcept { + // return pow(base, (double)v); + + bool neg; + unsigned exp; + if (expS < 0) { + neg = true; + exp = (unsigned) -expS; + } else { + neg = false; + exp = (unsigned) expS; + } + double v = 1.0; + if (exp) { + double mul = base; + for(;;) { + if (exp & 1) v *= mul; + exp >>= 1; + if (exp == 0) break; + mul *= mul; + } + } + if (neg) v = 1.0 / v; + return v; +} + + +t_int32 pfc::rint32(double p_val) { return (t_int32)lround(p_val); } +t_int64 pfc::rint64(double p_val) { return (t_int64)llround(p_val); } + + +// mem_block class +namespace pfc { + void mem_block::resize(size_t newSize) { + if (m_size != newSize) { + if (newSize == 0) { + free(m_ptr); m_ptr = nullptr; + } else if (m_size == 0) { + m_ptr = malloc( newSize ); + if (m_ptr == nullptr) throw std::bad_alloc(); + } else { + auto newptr = realloc( m_ptr, newSize ); + if (newptr == nullptr) throw std::bad_alloc(); + m_ptr = newptr; + } + + m_size = newSize; + } + } + void mem_block::clear() noexcept { + free(m_ptr); m_ptr = nullptr; m_size = 0; + } + void mem_block::move( mem_block & other ) noexcept { + clear(); + m_ptr = other.m_ptr; + m_size = other.m_size; + other._clear(); + } + void mem_block::copy( mem_block const & other ) { + const size_t size = other.size(); + resize( size ); + if (size > 0) memcpy(ptr(), other.ptr(), size); + } + + // aligned alloc + void alignedAlloc( void* & m_ptr, size_t & m_size, size_t s, size_t alignBytes) { + if (s == m_size) { + // nothing to do + } else if (s == 0) { + alignedFree(m_ptr); + m_ptr = NULL; + } else { + void * ptr; +#ifdef _MSC_VER + if (m_ptr == NULL) ptr = _aligned_malloc(s, alignBytes); + else ptr = _aligned_realloc(m_ptr, s, alignBytes); + if ( ptr == NULL ) throw std::bad_alloc(); +#else +#ifdef __ANDROID__ + if ((ptr = memalign( alignBytes, s )) == NULL) throw std::bad_alloc(); +#else + if (posix_memalign( &ptr, alignBytes, s ) < 0) throw std::bad_alloc(); +#endif + if (m_ptr != NULL) { + memcpy( ptr, m_ptr, min_t<size_t>( m_size, s ) ); + alignedFree( m_ptr ); + } +#endif + m_ptr = ptr; + } + m_size = s; + } + + void* alignedAlloc( size_t s, size_t alignBytes ) { + void * ptr; +#ifdef _MSC_VER + ptr = _aligned_malloc(s, alignBytes); + if (ptr == nullptr) throw std::bad_alloc(); +#else +#ifdef __ANDROID__ + if ((ptr = memalign( alignBytes, s )) == NULL) throw std::bad_alloc(); +#else + if (posix_memalign( &ptr, alignBytes, s ) < 0) throw std::bad_alloc(); +#endif +#endif + return ptr; + } + + void alignedFree( void * ptr ) { +#ifdef _MSC_VER + _aligned_free(ptr); +#else + free(ptr); +#endif + } +} + + +#include "once.h" + +namespace pfc { +#if PFC_CUSTOM_ONCE_FLAG + static pfc::once_flag_lite g_onceGuardGuard; + static mutex * g_onceGuard; + + static mutex & onceGuard() { + call_once(g_onceGuardGuard, [] { + g_onceGuard = new mutex(); + } ); + return * g_onceGuard; + } + + void call_once( once_flag & flag, std::function<void () > work ) { + + if ( flag.done ) return; + + mutex & guard = onceGuard(); + for ( ;; ) { + std::shared_ptr<pfc::event> waitFor; + { + insync(guard); + if ( flag.done ) { + PFC_ASSERT( ! flag.inProgress ); + return; + } + if ( flag.inProgress ) { + if ( ! flag.waitFor ) flag.waitFor = std::make_shared< event > (); + waitFor = flag.waitFor; + } else { + flag.inProgress = true; + } + } + + if ( waitFor ) { + waitFor->wait_for( -1 ); + continue; + } + + try { + work(); + } catch(...) { + insync( guard ); + PFC_ASSERT( ! flag.done ); + PFC_ASSERT( flag.inProgress ); + flag.inProgress = false; + if ( flag.waitFor ) { + flag.waitFor->set_state( true ); + flag.waitFor.reset(); + } + throw; + } + + // succeeded + insync( guard ); + PFC_ASSERT( ! flag.done ); + PFC_ASSERT( flag.inProgress ); + flag.inProgress = false; + flag.done = true; + if ( flag.waitFor ) { + flag.waitFor->set_state( true ); + flag.waitFor.reset(); + } + return; + } + } +#endif + void call_once( once_flag_lite & flag, std::function<void ()> work ) { + for ( ;; ) { + if ( flag.done ) return; + if (! threadSafeInt::exchangeHere(flag.guard, 1)) { + try { + work(); + } catch(...) { + flag.guard = 0; + throw; + } + flag.done = true; + return; + } + yield(); + } + } + + +#ifdef PFC_SET_THREAD_DESCRIPTION_EXTERNAL + static std::function<void (const char*)> g_setCurrentThreadDescription; + void initSetCurrentThreadDescription( std::function<void (const char*)> f ) { g_setCurrentThreadDescription = f; } +#endif + + void setCurrentThreadDescription( const char * msg ) { +#ifdef __APPLE__ + appleSetThreadDescription( msg ); +#endif + +#ifdef PFC_WINDOWS_DESKTOP_APP + winSetThreadDescription(GetCurrentThread(), pfc::stringcvt::string_wide_from_utf8( msg ) );; +#endif +#ifdef PFC_SET_THREAD_DESCRIPTION_EXTERNAL + if (g_setCurrentThreadDescription) g_setCurrentThreadDescription(msg); +#endif + } +} + +
