Mercurial > foo_out_sdl
comparison foosdk/sdk/pfc/primitives.h @ 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 #pragma once | |
| 2 | |
| 3 #include <functional> | |
| 4 | |
| 5 #include "traits.h" | |
| 6 #include "bit_array.h" | |
| 7 | |
| 8 #define tabsize(x) ((size_t)(sizeof(x)/sizeof(*x))) | |
| 9 #define PFC_TABSIZE(x) ((size_t)(sizeof(x)/sizeof(*x))) | |
| 10 | |
| 11 // Retained for compatibility. Do not use. Use C++11 template<typename ... arg_t> instead. | |
| 12 #define TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD_WITH_INITIALIZER(THISCLASS,MEMBER,INITIALIZER) \ | |
| 13 THISCLASS() : MEMBER() INITIALIZER \ | |
| 14 template<typename t_param1> THISCLASS(const t_param1 & p_param1) : MEMBER(p_param1) INITIALIZER \ | |
| 15 template<typename t_param1,typename t_param2> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2) : MEMBER(p_param1,p_param2) INITIALIZER \ | |
| 16 template<typename t_param1,typename t_param2,typename t_param3> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3) : MEMBER(p_param1,p_param2,p_param3) INITIALIZER \ | |
| 17 template<typename t_param1,typename t_param2,typename t_param3,typename t_param4> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4) : MEMBER(p_param1,p_param2,p_param3,p_param4) INITIALIZER \ | |
| 18 template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5) INITIALIZER \ | |
| 19 template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5,typename t_param6> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5,const t_param6 & p_param6) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5,p_param6) INITIALIZER \ | |
| 20 template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5,typename t_param6, typename t_param7> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5,const t_param6 & p_param6,const t_param7 & p_param7) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5,p_param6,p_param7) INITIALIZER \ | |
| 21 template<typename t_param1,typename t_param2,typename t_param3,typename t_param4,typename t_param5,typename t_param6, typename t_param7, typename t_param8> THISCLASS(const t_param1 & p_param1,const t_param2 & p_param2,const t_param3 & p_param3,const t_param4 & p_param4,const t_param5 & p_param5,const t_param6 & p_param6,const t_param7 & p_param7, const t_param8 & p_param8) : MEMBER(p_param1,p_param2,p_param3,p_param4,p_param5,p_param6,p_param7, p_param8) INITIALIZER | |
| 22 | |
| 23 #define TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD(THISCLASS,MEMBER) TEMPLATE_CONSTRUCTOR_FORWARD_FLOOD_WITH_INITIALIZER(THISCLASS,MEMBER,{}) | |
| 24 | |
| 25 | |
| 26 #ifdef _WIN32 | |
| 27 | |
| 28 #ifndef _MSC_VER | |
| 29 #error MSVC expected | |
| 30 #endif | |
| 31 | |
| 32 // MSVC specific - part of fb2k ABI - cannot ever change on MSVC/Windows | |
| 33 | |
| 34 #define PFC_DECLARE_EXCEPTION(NAME,BASECLASS,DEFAULTMSG) \ | |
| 35 class NAME : public BASECLASS { \ | |
| 36 public: \ | |
| 37 static const char * g_what() {return DEFAULTMSG;} \ | |
| 38 NAME() : BASECLASS(DEFAULTMSG,0) {} \ | |
| 39 NAME(const char * p_msg) : BASECLASS(p_msg) {} \ | |
| 40 NAME(const char * p_msg,int) : BASECLASS(p_msg,0) {} \ | |
| 41 NAME(const NAME & p_source) : BASECLASS(p_source) {} \ | |
| 42 }; | |
| 43 | |
| 44 namespace pfc { | |
| 45 template<typename t_exception> PFC_NORETURN inline void throw_exception_with_message(const char * p_message) { | |
| 46 throw t_exception(p_message); | |
| 47 } | |
| 48 } | |
| 49 | |
| 50 #else | |
| 51 | |
| 52 #define PFC_DECLARE_EXCEPTION(NAME,BASECLASS,DEFAULTMSG) \ | |
| 53 class NAME : public BASECLASS { \ | |
| 54 public: \ | |
| 55 static const char * g_what() {return DEFAULTMSG;} \ | |
| 56 const char* what() const throw() {return DEFAULTMSG;} \ | |
| 57 }; | |
| 58 | |
| 59 namespace pfc { | |
| 60 template<typename t_base> class __exception_with_message_t : public t_base { | |
| 61 private: typedef __exception_with_message_t<t_base> t_self; | |
| 62 public: | |
| 63 __exception_with_message_t(const char * p_message) : m_message(NULL) { | |
| 64 set_message(p_message); | |
| 65 } | |
| 66 __exception_with_message_t() : m_message(NULL) {} | |
| 67 __exception_with_message_t(const t_self & p_source) : m_message(NULL) {set_message(p_source.m_message);} | |
| 68 | |
| 69 const char* what() const throw() {return m_message != NULL ? m_message : "unnamed exception";} | |
| 70 | |
| 71 const t_self & operator=(const t_self & p_source) {set_message(p_source.m_message);} | |
| 72 | |
| 73 ~__exception_with_message_t() throw() {cleanup();} | |
| 74 | |
| 75 private: | |
| 76 void set_message(const char * p_message) throw() { | |
| 77 cleanup(); | |
| 78 if (p_message != NULL) m_message = strdup(p_message); | |
| 79 } | |
| 80 void cleanup() throw() { | |
| 81 if (m_message != NULL) {free(m_message); m_message = NULL;} | |
| 82 } | |
| 83 char * m_message; | |
| 84 }; | |
| 85 template<typename t_exception> PFC_NORETURN void throw_exception_with_message(const char * p_message) { | |
| 86 throw __exception_with_message_t<t_exception>(p_message); | |
| 87 } | |
| 88 } | |
| 89 #endif | |
| 90 | |
| 91 namespace pfc { | |
| 92 | |
| 93 template<typename p_type1,typename p_type2> class assert_same_type; | |
| 94 template<typename p_type> class assert_same_type<p_type,p_type> {}; | |
| 95 | |
| 96 template<typename p_type1,typename p_type2> | |
| 97 class is_same_type { public: enum {value = false}; }; | |
| 98 template<typename p_type> | |
| 99 class is_same_type<p_type,p_type> { public: enum {value = true}; }; | |
| 100 | |
| 101 template<bool val> class static_assert_t; | |
| 102 template<> class static_assert_t<true> {}; | |
| 103 | |
| 104 #define PFC_STATIC_ASSERT(X) { ::pfc::static_assert_t<(X)>(); } | |
| 105 | |
| 106 template<typename t_type> | |
| 107 void assert_raw_type() {static_assert_t< !traits_t<t_type>::needs_constructor && !traits_t<t_type>::needs_destructor >();} | |
| 108 | |
| 109 template<typename t_type> class assert_byte_type; | |
| 110 template<> class assert_byte_type<char> {}; | |
| 111 template<> class assert_byte_type<unsigned char> {}; | |
| 112 template<> class assert_byte_type<signed char> {}; | |
| 113 | |
| 114 | |
| 115 template<typename t_type> void __unsafe__memcpy_t(t_type * p_dst,const t_type * p_src,t_size p_count) { | |
| 116 ::memcpy(reinterpret_cast<void*>(p_dst), reinterpret_cast<const void*>(p_src), p_count * sizeof(t_type)); | |
| 117 } | |
| 118 | |
| 119 template<typename t_type> void __unsafe__in_place_destructor_t(t_type & p_item) throw() { | |
| 120 if constexpr (traits_t<t_type>::needs_destructor) try{ p_item.~t_type(); } catch(...) {} | |
| 121 } | |
| 122 | |
| 123 template<typename t_type> void __unsafe__in_place_constructor_t(t_type & p_item) { | |
| 124 if constexpr (traits_t<t_type>::needs_constructor) { | |
| 125 t_type * ret = new(&p_item) t_type; | |
| 126 PFC_ASSERT(ret == &p_item); | |
| 127 (void) ret; // suppress warning | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 template<typename t_type> void __unsafe__in_place_destructor_array_t(t_type * p_items, t_size p_count) throw() { | |
| 132 if constexpr (traits_t<t_type>::needs_destructor) { | |
| 133 t_type * walk = p_items; | |
| 134 for(t_size n=p_count;n;--n) __unsafe__in_place_destructor_t(*(walk++)); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 template<typename t_type> t_type * __unsafe__in_place_constructor_array_t(t_type * p_items,t_size p_count) { | |
| 139 if constexpr (traits_t<t_type>::needs_constructor) { | |
| 140 t_size walkptr = 0; | |
| 141 try { | |
| 142 for(walkptr=0;walkptr<p_count;++walkptr) __unsafe__in_place_constructor_t(p_items[walkptr]); | |
| 143 } catch(...) { | |
| 144 __unsafe__in_place_destructor_array_t(p_items,walkptr); | |
| 145 throw; | |
| 146 } | |
| 147 } | |
| 148 return p_items; | |
| 149 } | |
| 150 | |
| 151 template<typename t_type> t_type * __unsafe__in_place_resize_array_t(t_type * p_items,t_size p_from,t_size p_to) { | |
| 152 if (p_from < p_to) __unsafe__in_place_constructor_array_t(p_items + p_from, p_to - p_from); | |
| 153 else if (p_from > p_to) __unsafe__in_place_destructor_array_t(p_items + p_to, p_from - p_to); | |
| 154 return p_items; | |
| 155 } | |
| 156 | |
| 157 template<typename t_type,typename t_copy> void __unsafe__in_place_constructor_copy_t(t_type & p_item,const t_copy & p_copyfrom) { | |
| 158 if constexpr (traits_t<t_type>::needs_constructor) { | |
| 159 t_type * ret = new(&p_item) t_type(p_copyfrom); | |
| 160 PFC_ASSERT(ret == &p_item); | |
| 161 (void) ret; // suppress warning | |
| 162 } else { | |
| 163 p_item = p_copyfrom; | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 template<typename t_type,typename t_copy> t_type * __unsafe__in_place_constructor_array_copy_t(t_type * p_items,t_size p_count, const t_copy * p_copyfrom) { | |
| 168 t_size walkptr = 0; | |
| 169 try { | |
| 170 for(walkptr=0;walkptr<p_count;++walkptr) __unsafe__in_place_constructor_copy_t(p_items[walkptr],p_copyfrom[walkptr]); | |
| 171 } catch(...) { | |
| 172 __unsafe__in_place_destructor_array_t(p_items,walkptr); | |
| 173 throw; | |
| 174 } | |
| 175 return p_items; | |
| 176 } | |
| 177 | |
| 178 template<typename t_type,typename t_copy> t_type * __unsafe__in_place_constructor_array_copy_partial_t(t_type * p_items,t_size p_count, const t_copy * p_copyfrom,t_size p_copyfrom_count) { | |
| 179 if (p_copyfrom_count > p_count) p_copyfrom_count = p_count; | |
| 180 __unsafe__in_place_constructor_array_copy_t(p_items,p_copyfrom_count,p_copyfrom); | |
| 181 try { | |
| 182 __unsafe__in_place_constructor_array_t(p_items + p_copyfrom_count,p_count - p_copyfrom_count); | |
| 183 } catch(...) { | |
| 184 __unsafe__in_place_destructor_array_t(p_items,p_copyfrom_count); | |
| 185 throw; | |
| 186 } | |
| 187 return p_items; | |
| 188 } | |
| 189 | |
| 190 template<typename t_ret> t_ret implicit_cast(t_ret val) {return val;} | |
| 191 | |
| 192 template<typename t_ret,typename t_param> | |
| 193 t_ret * safe_ptr_cast(t_param * p_param) { | |
| 194 if constexpr (pfc::is_same_type<t_ret,t_param>::value) return p_param; | |
| 195 else { | |
| 196 if (p_param == NULL) return NULL; | |
| 197 else return p_param; | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 typedef std::exception exception; | |
| 202 | |
| 203 PFC_DECLARE_EXCEPTION(exception_overflow,exception,"Overflow"); | |
| 204 PFC_DECLARE_EXCEPTION(exception_bug_check,exception,"Bug check"); | |
| 205 PFC_DECLARE_EXCEPTION(exception_invalid_params,exception_bug_check,"Invalid parameters"); | |
| 206 PFC_DECLARE_EXCEPTION(exception_unexpected_recursion,exception_bug_check,"Unexpected recursion"); | |
| 207 PFC_DECLARE_EXCEPTION(exception_not_implemented,exception_bug_check,"Feature not implemented"); | |
| 208 PFC_DECLARE_EXCEPTION(exception_dynamic_assert,exception_bug_check,"dynamic_assert failure"); | |
| 209 | |
| 210 template<typename t_ret,typename t_param> | |
| 211 t_ret downcast_guarded(const t_param & p_param) { | |
| 212 t_ret temp = (t_ret) p_param; | |
| 213 if ((t_param) temp != p_param) throw exception_overflow(); | |
| 214 return temp; | |
| 215 } | |
| 216 | |
| 217 template<typename t_exception,typename t_ret,typename t_param> | |
| 218 t_ret downcast_guarded_ex(const t_param & p_param) { | |
| 219 t_ret temp = (t_ret) p_param; | |
| 220 if ((t_param) temp != p_param) throw t_exception(); | |
| 221 return temp; | |
| 222 } | |
| 223 | |
| 224 template<typename t_acc,typename t_add> | |
| 225 void accumulate_guarded(t_acc & p_acc, const t_add & p_add) { | |
| 226 t_acc delta = downcast_guarded<t_acc>(p_add); | |
| 227 delta += p_acc; | |
| 228 if (delta < p_acc) throw exception_overflow(); | |
| 229 p_acc = delta; | |
| 230 } | |
| 231 | |
| 232 //deprecated | |
| 233 inline void bug_check_assert(bool p_condition, const char * p_msg) { | |
| 234 if (!p_condition) { | |
| 235 PFC_ASSERT(0); | |
| 236 throw_exception_with_message<exception_bug_check>(p_msg); | |
| 237 } | |
| 238 } | |
| 239 //deprecated | |
| 240 inline void bug_check_assert(bool p_condition) { | |
| 241 if (!p_condition) { | |
| 242 PFC_ASSERT(0); | |
| 243 throw exception_bug_check(); | |
| 244 } | |
| 245 } | |
| 246 | |
| 247 inline void dynamic_assert(bool p_condition, const char * p_msg) { | |
| 248 if (!p_condition) { | |
| 249 PFC_ASSERT(0); | |
| 250 throw_exception_with_message<exception_dynamic_assert>(p_msg); | |
| 251 } | |
| 252 } | |
| 253 inline void dynamic_assert(bool p_condition) { | |
| 254 if (!p_condition) { | |
| 255 PFC_ASSERT(0); | |
| 256 throw exception_dynamic_assert(); | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 template<typename T> | |
| 261 inline void swap_multi_t(T * p_buffer1,T * p_buffer2,t_size p_size) { | |
| 262 T * walk1 = p_buffer1, * walk2 = p_buffer2; | |
| 263 for(t_size n=p_size;n;--n) { | |
| 264 T temp (* walk1); | |
| 265 *walk1 = *walk2; | |
| 266 *walk2 = temp; | |
| 267 walk1++; walk2++; | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 template<typename T,t_size p_size> | |
| 272 inline void swap_multi_t(T * p_buffer1,T * p_buffer2) { | |
| 273 T * walk1 = p_buffer1, * walk2 = p_buffer2; | |
| 274 for(t_size n=p_size;n;--n) { | |
| 275 T temp (* walk1); | |
| 276 *walk1 = *walk2; | |
| 277 *walk2 = temp; | |
| 278 walk1++; walk2++; | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 | |
| 283 template<t_size p_size> | |
| 284 inline void __unsafe__swap_raw_t(void * p_object1, void * p_object2) { | |
| 285 if constexpr (p_size % sizeof(t_size) == 0) { | |
| 286 swap_multi_t<t_size,p_size/sizeof(t_size)>(reinterpret_cast<t_size*>(p_object1),reinterpret_cast<t_size*>(p_object2)); | |
| 287 } else { | |
| 288 swap_multi_t<t_uint8,p_size>(reinterpret_cast<t_uint8*>(p_object1),reinterpret_cast<t_uint8*>(p_object2)); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 template<typename T> | |
| 293 inline void swap_t(T & p_item1, T & p_item2) { | |
| 294 if constexpr (traits_t<T>::realloc_safe) { | |
| 295 __unsafe__swap_raw_t<sizeof(T)>( reinterpret_cast<void*>( &p_item1 ), reinterpret_cast<void*>( &p_item2 ) ); | |
| 296 } else { | |
| 297 T temp( std::move(p_item2) ); | |
| 298 p_item2 = std::move(p_item1); | |
| 299 p_item1 = std::move(temp); | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 //! This is similar to plain p_item1 = p_item2; assignment, but optimized for the case where p_item2 content is no longer needed later on. This can be overridden for specific classes for optimal performance. \n | |
| 304 //! p_item2 value is undefined after performing a move_t. For an example, in certain cases move_t will fall back to swap_t. | |
| 305 template<typename T> | |
| 306 inline void move_t(T & p_item1, T & p_item2) { | |
| 307 p_item1 = std::move(p_item2); | |
| 308 } | |
| 309 | |
| 310 template<typename t_array> | |
| 311 t_size array_size_t(const t_array & p_array) {return p_array.get_size();} | |
| 312 | |
| 313 template<typename t_item, t_size p_width> | |
| 314 t_size array_size_t(const t_item (&p_array)[p_width]) {return p_width;} | |
| 315 | |
| 316 template<typename t_array, typename t_item> static bool array_isLast(const t_array & arr, const t_item & item) { | |
| 317 const t_size size = pfc::array_size_t(arr); | |
| 318 return size > 0 && arr[size-1] == item; | |
| 319 } | |
| 320 template<typename t_array, typename t_item> static bool array_isFirst(const t_array & arr, const t_item & item) { | |
| 321 const t_size size = pfc::array_size_t(arr); | |
| 322 return size > 0 && arr[0] == item; | |
| 323 } | |
| 324 | |
| 325 template<typename t_array,typename t_filler> | |
| 326 inline void fill_t(t_array & p_buffer,const t_size p_count, const t_filler & p_filler) { | |
| 327 for(t_size n=0;n<p_count;n++) | |
| 328 p_buffer[n] = p_filler; | |
| 329 } | |
| 330 | |
| 331 template<typename t_array,typename t_filler> | |
| 332 inline void fill_ptr_t(t_array * p_buffer,const t_size p_count, const t_filler & p_filler) { | |
| 333 for(t_size n=0;n<p_count;n++) | |
| 334 p_buffer[n] = p_filler; | |
| 335 } | |
| 336 | |
| 337 template<typename t_item1, typename t_item2> | |
| 338 inline int compare_t(const t_item1 & p_item1, const t_item2 & p_item2) { | |
| 339 if (p_item1 < p_item2) return -1; | |
| 340 else if (p_item1 > p_item2) return 1; | |
| 341 else return 0; | |
| 342 } | |
| 343 | |
| 344 //! For use with avltree/map etc. | |
| 345 class comparator_default { | |
| 346 public: | |
| 347 template<typename t_item1,typename t_item2> | |
| 348 inline static int compare(const t_item1 & p_item1,const t_item2 & p_item2) {return pfc::compare_t(p_item1,p_item2);} | |
| 349 }; | |
| 350 | |
| 351 template<typename t_comparator = pfc::comparator_default> class comparator_pointer { public: | |
| 352 template<typename t_item1,typename t_item2> static int compare(const t_item1 & p_item1,const t_item2 & p_item2) {return t_comparator::compare(*p_item1,*p_item2);} | |
| 353 }; | |
| 354 | |
| 355 template<typename t_primary,typename t_secondary> class comparator_dual { public: | |
| 356 template<typename t_item1,typename t_item2> static int compare(const t_item1 & p_item1,const t_item2 & p_item2) { | |
| 357 int state = t_primary::compare(p_item1,p_item2); | |
| 358 if (state != 0) return state; | |
| 359 return t_secondary::compare(p_item1,p_item2); | |
| 360 } | |
| 361 }; | |
| 362 | |
| 363 class comparator_memcmp { | |
| 364 public: | |
| 365 template<typename t_item1,typename t_item2> | |
| 366 inline static int compare(const t_item1 & p_item1,const t_item2 & p_item2) { | |
| 367 static_assert_t<sizeof(t_item1) == sizeof(t_item2)>(); | |
| 368 return memcmp(&p_item1,&p_item2,sizeof(t_item1)); | |
| 369 } | |
| 370 }; | |
| 371 | |
| 372 template<typename t_source1, typename t_source2> | |
| 373 t_size subtract_sorted_lists_calculate_count(const t_source1 & p_source1, const t_source2 & p_source2) { | |
| 374 t_size walk1 = 0, walk2 = 0, walk_out = 0; | |
| 375 const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size(); | |
| 376 for(;;) { | |
| 377 int state; | |
| 378 if (walk1 < max1 && walk2 < max2) { | |
| 379 state = pfc::compare_t(p_source1[walk1],p_source2[walk2]); | |
| 380 } else if (walk1 < max1) { | |
| 381 state = -1; | |
| 382 } else if (walk2 < max2) { | |
| 383 state = 1; | |
| 384 } else { | |
| 385 break; | |
| 386 } | |
| 387 if (state < 0) walk_out++; | |
| 388 if (state <= 0) walk1++; | |
| 389 if (state >= 0) walk2++; | |
| 390 } | |
| 391 return walk_out; | |
| 392 } | |
| 393 | |
| 394 //! Subtracts p_source2 contents from p_source1 and stores result in p_destination. Both source lists must be sorted. | |
| 395 //! Note: duplicates will be carried over (and ignored for p_source2). | |
| 396 template<typename t_destination, typename t_source1, typename t_source2> | |
| 397 void subtract_sorted_lists(t_destination & p_destination,const t_source1 & p_source1, const t_source2 & p_source2) { | |
| 398 p_destination.set_size(subtract_sorted_lists_calculate_count(p_source1,p_source2)); | |
| 399 t_size walk1 = 0, walk2 = 0, walk_out = 0; | |
| 400 const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size(); | |
| 401 for(;;) { | |
| 402 int state; | |
| 403 if (walk1 < max1 && walk2 < max2) { | |
| 404 state = pfc::compare_t(p_source1[walk1],p_source2[walk2]); | |
| 405 } else if (walk1 < max1) { | |
| 406 state = -1; | |
| 407 } else if (walk2 < max2) { | |
| 408 state = 1; | |
| 409 } else { | |
| 410 break; | |
| 411 } | |
| 412 | |
| 413 | |
| 414 if (state < 0) p_destination[walk_out++] = p_source1[walk1]; | |
| 415 if (state <= 0) walk1++; | |
| 416 if (state >= 0) walk2++; | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 template<typename t_source1, typename t_source2> | |
| 421 t_size merge_sorted_lists_calculate_count(const t_source1 & p_source1, const t_source2 & p_source2) { | |
| 422 t_size walk1 = 0, walk2 = 0, walk_out = 0; | |
| 423 const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size(); | |
| 424 for(;;) { | |
| 425 int state; | |
| 426 if (walk1 < max1 && walk2 < max2) { | |
| 427 state = pfc::compare_t(p_source1[walk1],p_source2[walk2]); | |
| 428 } else if (walk1 < max1) { | |
| 429 state = -1; | |
| 430 } else if (walk2 < max2) { | |
| 431 state = 1; | |
| 432 } else { | |
| 433 break; | |
| 434 } | |
| 435 if (state <= 0) walk1++; | |
| 436 if (state >= 0) walk2++; | |
| 437 walk_out++; | |
| 438 } | |
| 439 return walk_out; | |
| 440 } | |
| 441 | |
| 442 //! Merges p_source1 and p_source2, storing content in p_destination. Both source lists must be sorted. | |
| 443 //! Note: duplicates will be carried over. | |
| 444 template<typename t_destination, typename t_source1, typename t_source2> | |
| 445 void merge_sorted_lists(t_destination & p_destination,const t_source1 & p_source1, const t_source2 & p_source2) { | |
| 446 p_destination.set_size(merge_sorted_lists_calculate_count(p_source1,p_source2)); | |
| 447 t_size walk1 = 0, walk2 = 0, walk_out = 0; | |
| 448 const t_size max1 = p_source1.get_size(), max2 = p_source2.get_size(); | |
| 449 for(;;) { | |
| 450 int state; | |
| 451 if (walk1 < max1 && walk2 < max2) { | |
| 452 state = pfc::compare_t(p_source1[walk1],p_source2[walk2]); | |
| 453 } else if (walk1 < max1) { | |
| 454 state = -1; | |
| 455 } else if (walk2 < max2) { | |
| 456 state = 1; | |
| 457 } else { | |
| 458 break; | |
| 459 } | |
| 460 if (state < 0) { | |
| 461 p_destination[walk_out] = p_source1[walk1++]; | |
| 462 } else if (state > 0) { | |
| 463 p_destination[walk_out] = p_source2[walk2++]; | |
| 464 } else { | |
| 465 p_destination[walk_out] = p_source1[walk1]; | |
| 466 walk1++; walk2++; | |
| 467 } | |
| 468 walk_out++; | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 template<typename t_array, typename T> | |
| 473 inline t_size append_t(t_array & p_array, T && p_item) | |
| 474 { | |
| 475 t_size old_count = p_array.get_size(); | |
| 476 p_array.set_size(old_count + 1); | |
| 477 p_array[old_count] = std::forward<T>(p_item); | |
| 478 return old_count; | |
| 479 } | |
| 480 | |
| 481 template<typename t_array,typename T> | |
| 482 inline t_size append_swap_t(t_array & p_array,T & p_item) | |
| 483 { | |
| 484 t_size old_count = p_array.get_size(); | |
| 485 p_array.set_size(old_count + 1); | |
| 486 swap_t(p_array[old_count],p_item); | |
| 487 return old_count; | |
| 488 } | |
| 489 | |
| 490 template<typename t_array> | |
| 491 inline t_size insert_uninitialized_t(t_array & p_array,t_size p_index) { | |
| 492 t_size old_count = p_array.get_size(); | |
| 493 if (p_index > old_count) p_index = old_count; | |
| 494 p_array.set_size(old_count + 1); | |
| 495 for(t_size n=old_count;n>p_index;n--) move_t(p_array[n], p_array[n-1]); | |
| 496 return p_index; | |
| 497 } | |
| 498 | |
| 499 template<typename t_array,typename T> | |
| 500 inline t_size insert_t(t_array & p_array,const T & p_item,t_size p_index) { | |
| 501 t_size old_count = p_array.get_size(); | |
| 502 if (p_index > old_count) p_index = old_count; | |
| 503 p_array.set_size(old_count + 1); | |
| 504 for(t_size n=old_count;n>p_index;n--) | |
| 505 move_t(p_array[n], p_array[n-1]); | |
| 506 p_array[p_index] = p_item; | |
| 507 return p_index; | |
| 508 } | |
| 509 template<typename array1_t, typename array2_t> | |
| 510 void insert_array_t( array1_t & outArray, size_t insertAt, array2_t const & inArray, size_t inArraySize) { | |
| 511 const size_t oldSize = outArray.get_size(); | |
| 512 if (insertAt > oldSize) insertAt = oldSize; | |
| 513 const size_t newSize = oldSize + inArraySize; | |
| 514 outArray.set_size( newSize ); | |
| 515 for(size_t m = oldSize; m != insertAt; --m) { | |
| 516 move_t( outArray[ m - 1 + inArraySize], outArray[m - 1] ); | |
| 517 } | |
| 518 for(size_t w = 0; w < inArraySize; ++w) { | |
| 519 outArray[ insertAt + w ] = inArray[ w ]; | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 template<typename t_array,typename in_array_t> | |
| 524 inline t_size insert_multi_t(t_array & p_array,const in_array_t & p_items, size_t p_itemCount, t_size p_index) { | |
| 525 const t_size old_count = p_array.get_size(); | |
| 526 const size_t new_count = old_count + p_itemCount; | |
| 527 if (p_index > old_count) p_index = old_count; | |
| 528 p_array.set_size(new_count); | |
| 529 size_t toMove = old_count - p_index; | |
| 530 for(size_t w = 0; w < toMove; ++w) { | |
| 531 move_t( p_array[new_count - 1 - w], p_array[old_count - 1 - w] ); | |
| 532 } | |
| 533 | |
| 534 for(size_t w = 0; w < p_itemCount; ++w) { | |
| 535 p_array[p_index+w] = p_items[w]; | |
| 536 } | |
| 537 | |
| 538 return p_index; | |
| 539 } | |
| 540 template<typename t_array,typename T> | |
| 541 inline t_size insert_swap_t(t_array & p_array,T & p_item,t_size p_index) { | |
| 542 t_size old_count = p_array.get_size(); | |
| 543 if (p_index > old_count) p_index = old_count; | |
| 544 p_array.set_size(old_count + 1); | |
| 545 for(t_size n=old_count;n>p_index;n--) | |
| 546 swap_t(p_array[n],p_array[n-1]); | |
| 547 swap_t(p_array[p_index],p_item); | |
| 548 return p_index; | |
| 549 } | |
| 550 | |
| 551 | |
| 552 template<typename T> | |
| 553 inline T max_t(const T & item1, const T & item2) {return item1 > item2 ? item1 : item2;}; | |
| 554 | |
| 555 template<typename T> | |
| 556 inline T min_t(const T & item1, const T & item2) {return item1 < item2 ? item1 : item2;}; | |
| 557 | |
| 558 template<typename T> | |
| 559 inline T abs_t(T item) {return item<0 ? -item : item;} | |
| 560 | |
| 561 template<typename T> | |
| 562 inline T sqr_t(T item) {return item * item;} | |
| 563 | |
| 564 template<typename T> | |
| 565 inline T clip_t(const T & p_item, const T & p_min, const T & p_max) { | |
| 566 if (p_item < p_min) return p_min; | |
| 567 else if (p_item <= p_max) return p_item; | |
| 568 else return p_max; | |
| 569 } | |
| 570 | |
| 571 | |
| 572 | |
| 573 | |
| 574 | |
| 575 template<typename T> | |
| 576 inline void delete_t(T* ptr) {delete ptr;} | |
| 577 | |
| 578 template<typename T> | |
| 579 inline void delete_array_t(T* ptr) {delete[] ptr;} | |
| 580 | |
| 581 template<typename T> | |
| 582 inline T* clone_t(T* ptr) {return new T(*ptr);} | |
| 583 | |
| 584 | |
| 585 template<typename t_exception,typename t_int> | |
| 586 inline t_int mul_safe_t(t_int p_val1,t_int p_val2) { | |
| 587 if (p_val1 == 0 || p_val2 == 0) return 0; | |
| 588 t_int temp = (t_int) (p_val1 * p_val2); | |
| 589 if (temp / p_val1 != p_val2) throw t_exception(); | |
| 590 return temp; | |
| 591 } | |
| 592 template<typename t_int> | |
| 593 t_int multiply_guarded(t_int v1, t_int v2) { | |
| 594 return mul_safe_t<exception_overflow>(v1, v2); | |
| 595 } | |
| 596 template<typename t_int> t_int add_unsigned_clipped(t_int v1, t_int v2) { | |
| 597 t_int v = v1 + v2; | |
| 598 if (v < v1) return ~0; | |
| 599 return v; | |
| 600 } | |
| 601 template<typename t_int> t_int sub_unsigned_clipped(t_int v1, t_int v2) { | |
| 602 t_int v = v1 - v2; | |
| 603 if (v > v1) return 0; | |
| 604 return v; | |
| 605 } | |
| 606 template<typename t_int> void acc_unsigned_clipped(t_int & v1, t_int v2) { | |
| 607 v1 = add_unsigned_clipped(v1, v2); | |
| 608 } | |
| 609 | |
| 610 template<typename t_src,typename t_dst> | |
| 611 void memcpy_t(t_dst* p_dst,const t_src* p_src,t_size p_count) { | |
| 612 for(t_size n=0;n<p_count;n++) p_dst[n] = p_src[n]; | |
| 613 } | |
| 614 | |
| 615 template<typename t_dst,typename t_src> | |
| 616 void copy_array_loop_t(t_dst & p_dst,const t_src & p_src,t_size p_count) { | |
| 617 for(t_size n=0;n<p_count;n++) p_dst[n] = p_src[n]; | |
| 618 } | |
| 619 | |
| 620 template<typename t_src,typename t_dst> | |
| 621 void memcpy_backwards_t(t_dst * p_dst,const t_src * p_src,t_size p_count) { | |
| 622 p_dst += p_count; p_src += p_count; | |
| 623 for(t_size n=0;n<p_count;n++) *(--p_dst) = *(--p_src); | |
| 624 } | |
| 625 | |
| 626 template<typename T,typename t_val> | |
| 627 void memset_t(T * p_buffer,const t_val & p_val,t_size p_count) { | |
| 628 for(t_size n=0;n<p_count;n++) p_buffer[n] = p_val; | |
| 629 } | |
| 630 | |
| 631 template<typename T,typename t_val> | |
| 632 void memset_t(T &p_buffer,const t_val & p_val) { | |
| 633 const t_size width = pfc::array_size_t(p_buffer); | |
| 634 for(t_size n=0;n<width;n++) p_buffer[n] = p_val; | |
| 635 } | |
| 636 | |
| 637 template<typename T> | |
| 638 void memset_null_t(T * p_buffer,t_size p_count) { | |
| 639 for(t_size n=0;n<p_count;n++) p_buffer[n] = 0; | |
| 640 } | |
| 641 | |
| 642 template<typename T> | |
| 643 void memset_null_t(T &p_buffer) { | |
| 644 const t_size width = pfc::array_size_t(p_buffer); | |
| 645 for(t_size n=0;n<width;n++) p_buffer[n] = 0; | |
| 646 } | |
| 647 | |
| 648 template<typename T> | |
| 649 void memmove_t(T* p_dst,const T* p_src,t_size p_count) { | |
| 650 if (p_dst == p_src) {/*do nothing*/} | |
| 651 else if (p_dst > p_src && p_dst < p_src + p_count) memcpy_backwards_t<T>(p_dst,p_src,p_count); | |
| 652 else memcpy_t<T>(p_dst,p_src,p_count); | |
| 653 } | |
| 654 | |
| 655 template<typename TVal> void memxor_t(TVal * out, const TVal * s1, const TVal * s2, t_size count) { | |
| 656 for(t_size walk = 0; walk < count; ++walk) out[walk] = s1[walk] ^ s2[walk]; | |
| 657 } | |
| 658 inline static void memxor(void * target, const void * source1, const void * source2, t_size size) { | |
| 659 memxor_t( reinterpret_cast<t_uint8*>(target), reinterpret_cast<const t_uint8*>(source1), reinterpret_cast<const t_uint8*>(source2), size); | |
| 660 } | |
| 661 | |
| 662 template<typename T> | |
| 663 T* new_ptr_check_t(T* p_ptr) { | |
| 664 if (p_ptr == NULL) throw std::bad_alloc(); | |
| 665 return p_ptr; | |
| 666 } | |
| 667 | |
| 668 template<typename T> | |
| 669 int sgn_t(const T & p_val) { | |
| 670 if (p_val < 0) return -1; | |
| 671 else if (p_val > 0) return 1; | |
| 672 else return 0; | |
| 673 } | |
| 674 | |
| 675 template<typename T> const T* empty_string_t(); | |
| 676 | |
| 677 template<> inline const char * empty_string_t<char>() {return "";} | |
| 678 template<> inline const wchar_t * empty_string_t<wchar_t>() {return L"";} | |
| 679 | |
| 680 | |
| 681 template<typename type_t, typename arg_t> | |
| 682 type_t replace_t(type_t & p_var,arg_t && p_newval) { | |
| 683 auto oldval = std::move(p_var); | |
| 684 p_var = std::forward<arg_t>(p_newval); | |
| 685 return oldval; | |
| 686 } | |
| 687 | |
| 688 template<typename t_type> | |
| 689 t_type replace_null_t(t_type & p_var) { | |
| 690 t_type ret = std::move(p_var); | |
| 691 p_var = 0; | |
| 692 return ret; | |
| 693 } | |
| 694 | |
| 695 template<t_size p_size_pow2> | |
| 696 inline bool is_ptr_aligned_t(const void * p_ptr) { | |
| 697 static_assert_t< (p_size_pow2 & (p_size_pow2 - 1)) == 0 >(); | |
| 698 return ( ((t_size)p_ptr) & (p_size_pow2-1) ) == 0; | |
| 699 } | |
| 700 | |
| 701 | |
| 702 template<typename t_array> | |
| 703 void array_rangecheck_t(const t_array & p_array,t_size p_index) { | |
| 704 if (p_index >= pfc::array_size_t(p_array)) throw pfc::exception_overflow(); | |
| 705 } | |
| 706 | |
| 707 template<typename t_array> | |
| 708 void array_rangecheck_t(const t_array & p_array,t_size p_from,t_size p_to) { | |
| 709 if (p_from > p_to) throw pfc::exception_overflow(); | |
| 710 array_rangecheck_t(p_array,p_from); array_rangecheck_t(p_array,p_to); | |
| 711 } | |
| 712 | |
| 713 t_int32 rint32(double p_val); | |
| 714 t_int64 rint64(double p_val); | |
| 715 | |
| 716 //! Returns amount of items left. | |
| 717 template<typename array_t, typename pred_t> | |
| 718 inline size_t remove_if_t( array_t & arr, pred_t pred ) { | |
| 719 const size_t inCount = arr.size(); | |
| 720 size_t walk = 0; | |
| 721 | |
| 722 for (;; ) { | |
| 723 if ( walk == inCount ) return inCount; | |
| 724 if ( pred(arr[walk]) ) break; | |
| 725 ++ walk; | |
| 726 } | |
| 727 | |
| 728 size_t total = walk; | |
| 729 | |
| 730 ++ walk; // already know that at walk is pred() positive | |
| 731 | |
| 732 for( ; walk < inCount; ++ walk ) { | |
| 733 if ( !pred(arr[walk] ) ) { | |
| 734 move_t(arr[total++], arr[walk]); | |
| 735 } | |
| 736 } | |
| 737 arr.resize(total); | |
| 738 | |
| 739 return total; | |
| 740 } | |
| 741 | |
| 742 //! Returns amount of items left. | |
| 743 template<typename t_array> | |
| 744 inline t_size remove_mask_t(t_array & p_array,const bit_array & p_mask) | |
| 745 { | |
| 746 t_size n,count = p_array.size(), total = 0; | |
| 747 | |
| 748 n = total = p_mask.find(true,0,count); | |
| 749 | |
| 750 if (n<count) | |
| 751 { | |
| 752 for(n=p_mask.find(false,n+1,count-n-1);n<count;n=p_mask.find(false,n+1,count-n-1)) | |
| 753 move_t(p_array[total++],p_array[n]); | |
| 754 | |
| 755 p_array.resize(total); | |
| 756 | |
| 757 return total; | |
| 758 } | |
| 759 else return count; | |
| 760 } | |
| 761 | |
| 762 template<typename t_array,typename t_compare> | |
| 763 t_size find_duplicates_sorted_t(t_array p_array,t_size p_count,t_compare p_compare,bit_array_var & p_out) { | |
| 764 t_size ret = 0; | |
| 765 t_size n; | |
| 766 if (p_count > 0) | |
| 767 { | |
| 768 p_out.set(0,false); | |
| 769 for(n=1;n<p_count;n++) | |
| 770 { | |
| 771 bool found = p_compare(p_array[n-1],p_array[n]) == 0; | |
| 772 if (found) ret++; | |
| 773 p_out.set(n,found); | |
| 774 } | |
| 775 } | |
| 776 return ret; | |
| 777 } | |
| 778 | |
| 779 template<typename t_array,typename t_compare,typename t_permutation> | |
| 780 t_size find_duplicates_sorted_permutation_t(t_array p_array,t_size p_count,t_compare p_compare,t_permutation const & p_permutation,bit_array_var & p_out) { | |
| 781 t_size ret = 0; | |
| 782 t_size n; | |
| 783 if (p_count > 0) { | |
| 784 p_out.set(p_permutation[0],false); | |
| 785 for(n=1;n<p_count;n++) | |
| 786 { | |
| 787 bool found = p_compare(p_array[p_permutation[n-1]],p_array[p_permutation[n]]) == 0; | |
| 788 if (found) ret++; | |
| 789 p_out.set(p_permutation[n],found); | |
| 790 } | |
| 791 } | |
| 792 return ret; | |
| 793 } | |
| 794 | |
| 795 template<typename t_char> | |
| 796 t_size strlen_t(const t_char * p_string,t_size p_length = ~0) { | |
| 797 for(t_size walk = 0;;walk++) { | |
| 798 if (walk >= p_length || p_string[walk] == 0) return walk; | |
| 799 } | |
| 800 } | |
| 801 | |
| 802 | |
| 803 template<typename t_array> | |
| 804 class __list_to_array_enumerator { | |
| 805 public: | |
| 806 __list_to_array_enumerator(t_array & p_array) : m_walk(), m_array(p_array) {} | |
| 807 template<typename t_item> | |
| 808 void operator() (const t_item & p_item) { | |
| 809 PFC_ASSERT(m_walk < m_array.get_size()); | |
| 810 m_array[m_walk++] = p_item; | |
| 811 } | |
| 812 void finalize() { | |
| 813 PFC_ASSERT(m_walk == m_array.get_size()); | |
| 814 } | |
| 815 private: | |
| 816 t_size m_walk; | |
| 817 t_array & m_array; | |
| 818 }; | |
| 819 | |
| 820 template<typename t_list,typename t_array> | |
| 821 void list_to_array(t_array & p_array,const t_list & p_list) { | |
| 822 p_array.set_size(p_list.get_count()); | |
| 823 __list_to_array_enumerator<t_array> enumerator(p_array); | |
| 824 p_list.enumerate(enumerator); | |
| 825 enumerator.finalize(); | |
| 826 } | |
| 827 | |
| 828 template<typename t_receiver> | |
| 829 class enumerator_add_item { | |
| 830 public: | |
| 831 enumerator_add_item(t_receiver & p_receiver) : m_receiver(p_receiver) {} | |
| 832 template<typename t_item> void operator() (const t_item & p_item) {m_receiver.add_item(p_item);} | |
| 833 private: | |
| 834 t_receiver & m_receiver; | |
| 835 }; | |
| 836 | |
| 837 template<typename t_receiver,typename t_giver> | |
| 838 void overwrite_list_enumerated(t_receiver & p_receiver,const t_giver & p_giver) { | |
| 839 enumerator_add_item<t_receiver> wrapper(p_receiver); | |
| 840 p_giver.enumerate(wrapper); | |
| 841 } | |
| 842 | |
| 843 template<typename t_receiver,typename t_giver> | |
| 844 void copy_list_enumerated(t_receiver & p_receiver,const t_giver & p_giver) { | |
| 845 p_receiver.remove_all(); | |
| 846 overwrite_list_enumerated(p_receiver,p_giver); | |
| 847 } | |
| 848 | |
| 849 inline bool lxor(bool p_val1,bool p_val2) { | |
| 850 return p_val1 == !p_val2; | |
| 851 } | |
| 852 | |
| 853 template<typename t_val> | |
| 854 inline void min_acc(t_val & p_acc,const t_val & p_val) { | |
| 855 if (p_val < p_acc) p_acc = p_val; | |
| 856 } | |
| 857 | |
| 858 template<typename t_val> | |
| 859 inline void max_acc(t_val & p_acc,const t_val & p_val) { | |
| 860 if (p_val > p_acc) p_acc = p_val; | |
| 861 } | |
| 862 | |
| 863 t_uint64 pow_int(t_uint64 base, t_uint64 exp) noexcept; | |
| 864 double exp_int(double base, int exp) noexcept; | |
| 865 | |
| 866 | |
| 867 template<typename t_val> | |
| 868 class incrementScope { | |
| 869 public: | |
| 870 incrementScope(t_val & i) : v(i) {++v;} | |
| 871 ~incrementScope() {--v;} | |
| 872 private: | |
| 873 t_val & v; | |
| 874 }; | |
| 875 template<typename obj_t> | |
| 876 incrementScope<obj_t> autoIncrement(obj_t& v) { return incrementScope<obj_t>(v); } | |
| 877 | |
| 878 constexpr inline unsigned countBits32(uint32_t i) { | |
| 879 const uint32_t mask = 0x11111111; | |
| 880 uint32_t acc = i & mask; | |
| 881 acc += (i >> 1) & mask; | |
| 882 acc += (i >> 2) & mask; | |
| 883 acc += (i >> 3) & mask; | |
| 884 | |
| 885 const uint32_t mask2 = 0x0F0F0F0F; | |
| 886 uint32_t acc2 = acc & mask2; | |
| 887 acc2 += (acc >> 4) & mask2; | |
| 888 | |
| 889 const uint32_t mask3 = 0x00FF00FF; | |
| 890 uint32_t acc3 = acc2 & mask3; | |
| 891 acc3 += (acc2 >> 8) & mask3; | |
| 892 | |
| 893 return (acc3 & 0xFFFF) + ((acc3 >> 16) & 0xFFFF); | |
| 894 } | |
| 895 | |
| 896 // Forward declarations | |
| 897 template<typename t_to,typename t_from> | |
| 898 void copy_array_t(t_to & p_to,const t_from & p_from); | |
| 899 | |
| 900 template<typename t_array,typename t_value> | |
| 901 void fill_array_t(t_array & p_array,const t_value & p_value); | |
| 902 | |
| 903 // Generic no-op for breakpointing stuff | |
| 904 inline void nop() {} | |
| 905 | |
| 906 template<class T> | |
| 907 class vartoggle_t { | |
| 908 T oldval; T& var; | |
| 909 public: | |
| 910 vartoggle_t(const vartoggle_t&) = delete; | |
| 911 void operator=(const vartoggle_t&) = delete; | |
| 912 template<typename arg_t> | |
| 913 vartoggle_t(T& p_var, arg_t&& val) : var(p_var) { | |
| 914 oldval = std::move(var); | |
| 915 var = std::forward<arg_t>(val); | |
| 916 } | |
| 917 ~vartoggle_t() { var = std::move(oldval); } | |
| 918 }; | |
| 919 | |
| 920 template<typename T, typename arg_t> | |
| 921 vartoggle_t<T> autoToggle(T& p_var, arg_t&& val) { | |
| 922 return vartoggle_t<T>(p_var, std::forward<arg_t>(val)); | |
| 923 } | |
| 924 | |
| 925 template<class T> | |
| 926 class vartoggle_volatile_t { | |
| 927 T oldval; volatile T& var; | |
| 928 public: | |
| 929 template<typename arg_t> | |
| 930 vartoggle_volatile_t(volatile T& p_var, arg_t && val) : var(p_var) { | |
| 931 oldval = std::move(var); | |
| 932 var = std::forward<arg_t>(val); | |
| 933 } | |
| 934 ~vartoggle_volatile_t() { var = std::move(oldval); } | |
| 935 }; | |
| 936 | |
| 937 typedef vartoggle_t<bool> booltoggle; | |
| 938 | |
| 939 template<typename obj_t> | |
| 940 class singleton { | |
| 941 public: | |
| 942 static obj_t instance; | |
| 943 }; | |
| 944 template<typename obj_t> | |
| 945 obj_t singleton<obj_t>::instance; | |
| 946 | |
| 947 }; | |
| 948 #define PFC_SINGLETON(X) ::pfc::singleton<X>::instance | |
| 949 | |
| 950 | |
| 951 #define PFC_CLASS_NOT_COPYABLE(THISCLASSNAME,THISTYPE) \ | |
| 952 THISCLASSNAME(const THISTYPE&) = delete; \ | |
| 953 const THISTYPE & operator=(const THISTYPE &) = delete; | |
| 954 | |
| 955 #define PFC_CLASS_NOT_COPYABLE_EX(THISTYPE) PFC_CLASS_NOT_COPYABLE(THISTYPE,THISTYPE) | |
| 956 | |
| 957 | |
| 958 namespace pfc { | |
| 959 template<typename t_char> | |
| 960 t_size strlen_max_t(const t_char* ptr, t_size max) noexcept { | |
| 961 PFC_ASSERT(ptr != NULL || max == 0); | |
| 962 t_size n = 0; | |
| 963 while (n < max && ptr[n] != 0) n++; | |
| 964 return n; | |
| 965 } | |
| 966 | |
| 967 inline t_size strlen_max(const char* ptr, t_size max) noexcept { return strlen_max_t(ptr, max); } | |
| 968 inline t_size wcslen_max(const wchar_t* ptr, t_size max) noexcept { return strlen_max_t(ptr, max); } | |
| 969 | |
| 970 #ifdef _WINDOWS | |
| 971 inline t_size tcslen_max(const TCHAR* ptr, t_size max) noexcept { return strlen_max_t(ptr, max); } | |
| 972 #endif | |
| 973 } | |
| 974 | |
| 975 namespace pfc { | |
| 976 class autoScope { | |
| 977 public: | |
| 978 autoScope() {} | |
| 979 autoScope(std::function<void()>&& f) : m_cleanup(std::move(f)) {} | |
| 980 | |
| 981 template<typename what_t> void increment(what_t& obj) { | |
| 982 reset(); | |
| 983 ++obj; | |
| 984 m_cleanup = [&obj] { --obj; }; | |
| 985 } | |
| 986 template<typename what_t, typename arg_t> void toggle(what_t& obj, arg_t && val) { | |
| 987 reset(); | |
| 988 what_t old = obj; | |
| 989 obj = std::forward<arg_t>(val); | |
| 990 m_cleanup = [v = std::move(old), &obj]{ | |
| 991 obj = std::move(v); | |
| 992 }; | |
| 993 } | |
| 994 void operator() (std::function<void()>&& f) { | |
| 995 reset(); m_cleanup = std::move(f); | |
| 996 } | |
| 997 | |
| 998 ~autoScope() { | |
| 999 if (m_cleanup) m_cleanup(); | |
| 1000 } | |
| 1001 | |
| 1002 void cancel() { | |
| 1003 m_cleanup = nullptr; | |
| 1004 } | |
| 1005 | |
| 1006 void reset() { | |
| 1007 if (m_cleanup) { | |
| 1008 m_cleanup(); | |
| 1009 m_cleanup = nullptr; | |
| 1010 } | |
| 1011 } | |
| 1012 | |
| 1013 autoScope(const autoScope&) = delete; | |
| 1014 void operator=(const autoScope&) = delete; | |
| 1015 | |
| 1016 operator bool() const { return !!m_cleanup; } | |
| 1017 private: | |
| 1018 std::function<void()> m_cleanup; | |
| 1019 }; | |
| 1020 typedef autoScope onLeaving; | |
| 1021 } |
