|
1
|
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
|