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