2023-12-01 09:17:09 +00:00
// utilities for platform ...
//
// Date: 2023-06-30
//
# pragma once
# include "plat_types.h"
# include <string>
# include <memory>
# include <mutex>
# include <thread>
# include <vector>
# include <algorithm>
# include <deque>
# include <functional>
# define USE_SAFE_THREAD
enum log_type
{
LOG_TYPE_NONE = 0 , // no logging
LOG_TYPE_CONSOLE , // print to console
LOG_TYPE_FILE , // write log into file
} ;
enum log_level
{
LOG_LEVEL_ALL = 0 ,
LOG_LEVEL_DEBUG ,
LOG_LEVEL_WARNING ,
LOG_LEVEL_FATAL ,
} ;
namespace utils
{
std : : string utf82ansi ( const char * utf8 ) ;
std : : string ansi2utf8 ( const char * ansi ) ;
2024-02-08 09:33:22 +00:00
// Function: parse ONE character from a utf8 string
//
// Parameters: str - [in]: head of utf8 string
//
// [out]: beginning of the next character if success or no changes on failure
//
// ch - to receive the character, at least 8 bytes
//
// Return: 0 - success
// EINVAL - invalid utf8 string
// ENODATA - need more data
int parse_utf8_char ( const char * & str , char ch [ 8 ] ) ;
// Function: transfere from utf16 to utf8
//
// Parameters: in - [in]: head of utf16 beginning
//
// [out]: beginning of the next character if success or no changes on failure
// ch - to receive the character, at least 8 bytes
//
// Return: 0 - success
// EINVAL - invalid utf8 string
// ENODATA - need more data
int utf16_2_8 ( unsigned short * & in , char ch [ 8 ] ) ;
2023-12-01 09:17:09 +00:00
std : : string get_command_result ( const char * cmd , int len = - 1 , int * err = nullptr ) ;
std : : string get_local_data_path ( void ) ;
std : : string temporary_path ( void ) ;
std : : string format_current_time ( void ) ;
std : : string get_module_full_path ( const char * part_name = nullptr /*nullptr to get main-pe/first module's full path*/ ) ;
std : : string find_file ( const char * root_dir , const char * part_name , bool recursive = false ) ;
std : : string target_file_from_link ( const char * lnk_file ) ;
2024-01-30 03:43:06 +00:00
std : : string from_console ( const char * tips = nullptr , console_color clr = console_color : : COLOR_CHAR_GREEN ) ;
2023-12-01 09:17:09 +00:00
std : : string get_ini_value ( const char * seg , const char * key , const char * cfg_file ) ; // return "" if not found
std : : string load_mini_file ( const char * file , int * err ) ; // <= 1MB
int save_2_file ( void * data , size_t len , const char * file , bool append = false /*append or new*/ , size_t max_size = - 1 /*in append mode, truncate file if size is exceeded this value if was not -1*/ ) ;
2024-01-30 03:43:06 +00:00
void printf_with_color ( const char * msg , console_color text_clr , console_color bkg_clr = COLOR_BKG_NONE , console_display_mode mode = console_display_mode : : MODE_DEFAULT ) ;
2023-12-01 09:17:09 +00:00
bool is_match_pattern ( const char * text , const char * pattern ) ;
const char * to_lower ( std : : string & str ) ; // return str.c_str()
const char * trim ( std : : string & str , const char * sp = " \r \n \t " ) ; // return str.c_str()
2023-12-18 01:39:48 +00:00
bool from_hex_string ( const char * hex , uint8_t * val ) ;
bool from_hex_string ( const char * hex , uint16_t * val ) ;
bool from_hex_string ( const char * hex , uint32_t * val ) ;
bool from_hex_string ( const char * hex , uint64_t * val ) ;
2023-12-01 09:17:09 +00:00
HMODULE load_dll ( const char * path_file , int flag ) ;
bool create_folder ( const char * folder ) ;
void set_ini_value ( const char * seg , const char * key , const char * val , const char * cfg_file ) ;
int enum_file ( const char * folder , bool recursive , bool /*return false to stop enumeration*/ ( STDCALL * found ) ( const char * path_name , bool dir , void * param ) , void * param ) ;
int move_file ( const char * from , const char * to ) ;
2023-12-09 10:21:05 +00:00
int make_file_size ( const char * file , uint64_t size ) ; // truncate or extend file size to 'size', create if not exist
2023-12-01 09:17:09 +00:00
2024-01-23 07:07:17 +00:00
int get_memory_usage ( uint64_t * peak , uint64_t * now , uint64_t * phymem , uint32_t pid = - 1 ) ;
void print_memory_usage ( const char * tips , bool to_log_file ) ;
2023-12-01 09:17:09 +00:00
int get_disk_space ( const char * path , unsigned long long * total , unsigned long long * avail , unsigned long long * block ) ;
unsigned int get_page_size ( unsigned int * map_unit = nullptr ) ;
2023-12-09 10:21:05 +00:00
// return logging file path if 'type' was LOG_TYPE_FILE
std : : string init_log ( log_type type , log_level level = LOG_LEVEL_ALL , const char * fn_appendix = nullptr /*appendix to default log-file-name*/ ) ;
2023-12-01 09:17:09 +00:00
void uninit ( void ) ;
void log_info ( const char * info , int level = LOG_LEVEL_ALL ) ;
void log_mem_info ( const char * desc , const void * data , size_t bytes , int level = LOG_LEVEL_ALL ) ; // log as 0x12345678 00 01 02 ...
int get_log_type ( void ) ;
int get_log_level ( void ) ;
int copy_log_file_to ( const char * dst ) ;
int clear_log_file ( void ) ;
2024-01-11 09:59:23 +00:00
// unit convert ...
int mm_2_pixel ( float mm , int dpi = 200 ) ;
float pixel_2_mm ( int px , int dpi = 200 ) ;
2024-01-05 09:36:50 +00:00
// bitmap header ...
std : : string bitmap_info_header ( int pixel_w , int pixel_h , int bpp , int dpix , int dpiy = 0 ) ; // return BITMPINFOHEADER + pallete if need. dpiy same as dpix if was ZERO
std : : string bitmap_file_header ( BITMAPINFOHEADER * lpbi ) ; // return BITMAPFILEHEADER
2023-12-01 09:17:09 +00:00
# if OS_WIN
// Function: pump message recycle (GetMessageW)
//
// Parameters: hwnd - target window
//
// filter_min - the minimal message
//
// filter_max - the maximal message
//
// msghandler - custom message processor
// MSG*, received message by GetMessage
// bool*, return whether user handled the message, no TranslateMessage and DispatchMessage if this was true
//
// Return: whether quit the message recycle
bool run_get_message ( HWND hwnd , UINT filter_min = 0 , UINT filter_max = 0 , std : : function < bool ( MSG * , bool * ) > msghandler = std : : function < bool ( MSG * , bool * ) > ( ) ) ;
# endif
2023-12-19 07:27:16 +00:00
template < typename . . . Args >
std : : string format_string ( const char * fmt , Args . . . args )
{
size_t size = snprintf ( nullptr , 0 , fmt , args . . . ) + 2 ;
std : : unique_ptr < char [ ] > buf ( new char [ size ] ) ;
snprintf ( buf . get ( ) , size , fmt , args . . . ) ;
return buf . get ( ) ;
}
2023-12-01 09:17:09 +00:00
template < typename . . . Args >
void to_log ( int level , const char * fmt , Args . . . args )
{
if ( get_log_type ( ) ! = LOG_TYPE_NONE & & get_log_level ( ) < = level )
{
size_t size = snprintf ( nullptr , 0 , fmt , args . . . ) + 2 ;
std : : unique_ptr < char [ ] > buf ( new char [ size ] ) ;
snprintf ( buf . get ( ) , size , fmt , args . . . ) ;
log_info ( buf . get ( ) , ( log_level ) level ) ;
}
}
template < typename . . . Args >
void to_log_with_api ( bool ( * is_enable ) ( int ) , void ( * log_api ) ( const char * , int ) , int level , const char * fmt , Args . . . args )
{
if ( is_enable ( level ) )
{
size_t size = snprintf ( nullptr , 0 , fmt , args . . . ) + 2 ;
std : : unique_ptr < char [ ] > buf ( new char [ size ] ) ;
snprintf ( buf . get ( ) , size , fmt , args . . . ) ;
log_api ( buf . get ( ) , ( log_level ) level ) ;
}
}
template < class T >
T swap_half ( T v )
{
T mask = ( 1 < < ( sizeof ( T ) * 4 ) ) - 1 ,
h = v & mask ;
v > > = sizeof ( T ) * 4 ;
v & = mask ;
h < < = sizeof ( T ) * 4 ;
v | = h ;
return v ;
}
class base64
{
char base64_ind_ [ 128 ] ;
char base64_char_ [ 80 ] ;
char padding_char_ ;
bool is_valid_base64_table ( const char * table ) ;
bool initialize_base64_table ( const char * table ) ;
public :
base64 ( ) ;
~ base64 ( ) ;
public :
bool set_base64_table ( const char * table = nullptr ) ;
std : : string encode ( const char * data , size_t bytes , unsigned int line_bytes = - 1 , bool need_padding = true ) ;
std : : string decode ( const char * data , size_t bytes ) ;
} ;
} ;
# if OS_WIN
struct _time_val
{
time_t tv_sec ; /* Seconds. */
time_t tv_usec ; /* Microseconds. */
} ;
typedef struct _time_val TIMEV ;
struct timezone
{
int tz_minuteswest ; /* Minutes west of GMT. */
int tz_dsttime ; /* Nonzero if DST is ever in effect. */
} ;
int gettimeofday ( TIMEV * tv , struct timezone * tz ) ;
# else
# include <sys/time.h>
typedef struct timeval TIMEV ;
# endif
// object life referer
//
// derived from 'refer' if your class used in multi-threads
//
# define MUTEX std::mutex
# define LOCK_WITH_NAME(n, v) std::lock_guard<MUTEX> n(v)
# define SIMPLE_LOCK(v) LOCK_WITH_NAME(locker, v)
class refer
{
volatile int32_t ref_ ;
MUTEX mutex_ ;
protected :
refer ( ) ;
virtual ~ refer ( ) ;
virtual void on_born ( void ) ;
virtual void on_dead ( void ) ;
public :
virtual int32_t add_ref ( void ) ;
virtual int32_t release ( void ) ;
} ;
2024-01-23 07:07:17 +00:00
template < class T >
class refer_guard
{
T * obj_ = nullptr ;
void clear ( void )
{
if ( obj_ )
obj_ - > release ( ) ;
obj_ = nullptr ;
}
public :
refer_guard ( )
{ }
refer_guard ( T * obj ) : obj_ ( obj )
{ }
~ refer_guard ( )
{
clear ( ) ;
}
public :
void reset ( T * obj )
{
clear ( ) ;
obj_ = obj ;
}
T * operator - > ( void )
{
return obj_ ;
}
} ;
2023-12-01 09:17:09 +00:00
// time utility
class chronograph
{
TIMEV bgn_ ;
public :
chronograph ( ) ;
~ chronograph ( ) ;
static bool now ( TIMEV * tv ) ;
static bool now ( uint64_t * seconds , uint64_t * u_seconds ) ;
static std : : string now ( bool with_ms = true /*whether with milliseconds*/ ) ; // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false
public :
uint64_t elapse_s ( void ) ;
uint64_t elapse_ms ( void ) ;
uint64_t elapse_us ( void ) ;
void reset ( void ) ;
} ;
2024-01-05 09:36:50 +00:00
// global info
class global_info
{
public :
global_info ( ) ;
~ global_info ( ) ;
public :
static uint32_t page_size ;
static uint32_t page_map_size ;
static uint32_t cluster_size ;
static uint32_t gray_pallete [ 256 ] ;
} ;
2023-12-01 09:17:09 +00:00
// event
class platform_event : public refer
{
sem_t sem_ ;
volatile bool waiting_ ;
std : : string dbg_info_ ;
bool log_ = true ;
public :
platform_event ( const char * info = " " ) ;
~ platform_event ( ) ;
public :
bool try_wait ( void ) ;
bool wait ( unsigned timeout = USB_TIMEOUT_INFINITE /*ms*/ ) ; // USB_TIMEOUT_INFINITE is waiting unfinite, true when watied and false for wait timeout
void trigger ( void ) ;
2024-01-19 08:54:58 +00:00
void reset ( void ) ;
2023-12-01 09:17:09 +00:00
bool is_waiting ( void ) ;
void enable_log ( bool enable ) ;
void set_debug_info ( const char * info ) ;
} ;
// share memory
class shared_memory : public refer
{
unsigned long long key_ ;
void * obj_ ;
bool first_ ;
size_t bytes_ ;
size_t len_ ;
void init ( void ) ;
void clear ( void ) ;
char * get_buf ( void ) ;
void release_buf ( void * buf ) ;
# if !defined(WIN32) && !defined(_WIN64)
static std : : string get_proc_name_by_pid ( pid_t pid ) ;
# endif
public :
shared_memory ( unsigned long long key , size_t size = 1024 ) ;
protected :
~ shared_memory ( ) ;
public :
bool is_ok ( void ) ;
bool is_first ( void ) ;
std : : string read ( void ) ;
int write ( const char * data , size_t len ) ;
} ;
template < class T >
class safe_fifo
{
MUTEX lock_ ;
std : : deque < T > que_ ;
platform_event * wait_ ;
public :
safe_fifo ( const char * who ) : wait_ ( new platform_event ( who & & * who ? who : " fifo " ) )
{ }
~ safe_fifo ( )
{
wait_ - > release ( ) ;
}
public :
size_t save ( const T & t , bool notify = false )
{
SIMPLE_LOCK ( lock_ ) ;
size_t cnt = que_ . size ( ) ;
que_ . push_back ( std : : move ( t ) ) ;
if ( notify )
wait_ - > trigger ( ) ;
return cnt + 1 ;
}
2024-01-19 08:54:58 +00:00
bool take ( T & t , bool wait = false , uint32_t to_ms = USB_TIMEOUT_INFINITE )
2023-12-01 09:17:09 +00:00
{
if ( wait & & size ( ) = = 0 )
{
2024-01-19 08:54:58 +00:00
if ( ! wait_ - > wait ( to_ms ) )
return false ;
2023-12-01 09:17:09 +00:00
}
{
SIMPLE_LOCK ( lock_ ) ;
if ( que_ . size ( ) )
{
t = std : : move ( que_ . front ( ) ) ;
que_ . pop_front ( ) ;
return true ;
}
else
{
return false ;
}
}
}
2024-01-27 09:43:13 +00:00
T front ( void )
{
SIMPLE_LOCK ( lock_ ) ;
return que_ . front ( ) ;
}
void pop_front ( void )
{
SIMPLE_LOCK ( lock_ ) ;
que_ . pop_front ( ) ;
}
2023-12-01 09:17:09 +00:00
size_t size ( void )
{
SIMPLE_LOCK ( lock_ ) ;
return que_ . size ( ) ;
}
void clear ( void )
{
SIMPLE_LOCK ( lock_ ) ;
que_ . clear ( ) ;
2024-01-19 08:54:58 +00:00
wait_ - > reset ( ) ;
2023-12-01 09:17:09 +00:00
}
void trigger ( void )
{
wait_ - > trigger ( ) ;
}
void enable_wait_log ( bool enable )
{
wait_ - > enable_log ( enable ) ;
}
} ;
class safe_thread
{
typedef struct _safe_thrd
{
std : : string name ;
std : : shared_ptr < std : : thread > thread ;
} SAFETHRD ;
volatile bool run_ = true ;
MUTEX lock_ ;
std : : unique_ptr < std : : thread > notify_thread_ ;
std : : vector < SAFETHRD > threads_ ;
safe_fifo < std : : string > excep_que_ ;
std : : function < void ( const char * ) > excep_handler_ = std : : function < void ( const char * ) > ( ) ;
2023-12-09 10:21:05 +00:00
void thread_worker ( std : : function < void ( void ) > func , std : : string name , void * addr ) ;
2023-12-01 09:17:09 +00:00
void thread_notify_exception ( void ) ;
public :
safe_thread ( void ) ;
~ safe_thread ( ) ;
public :
void set_exception_handler ( std : : function < void ( const char * ) > on_exception = std : : function < void ( const char * ) > ( ) ) ;
2023-12-09 10:21:05 +00:00
int start ( std : : function < void ( void ) > f , const char * thread_name , void * addr = nullptr ) ;
2023-12-01 09:17:09 +00:00
int stop ( const char * thread_name ) ;
} ;