2015-06-20 22:26:51 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2015-06-20 22:26:51 +02:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# ifndef utilsH
# define utilsH
//---------------------------------------------------------------------------
2020-05-19 08:53:38 +02:00
# include "config.h"
2021-10-04 07:53:58 +02:00
# include <algorithm>
2022-09-27 20:06:15 +02:00
# include <array>
2017-05-27 04:33:47 +02:00
# include <cstddef>
2023-08-31 11:54:46 +02:00
# include <cstdint>
2021-10-04 07:53:58 +02:00
# include <initializer_list>
2023-04-08 22:29:09 +02:00
# include <limits>
# include <stdexcept>
2017-05-27 04:33:47 +02:00
# include <string>
2020-05-14 14:45:35 +02:00
# include <vector>
2015-11-29 13:23:13 +01:00
2021-01-11 18:47:38 +01:00
struct SelectMapKeys {
2021-08-07 20:51:18 +02:00
template < class Pair >
2021-01-12 21:28:56 +01:00
typename Pair : : first_type operator ( ) ( const Pair & p ) const {
2021-01-11 18:47:38 +01:00
return p . first ;
}
} ;
struct SelectMapValues {
2021-08-07 20:51:18 +02:00
template < class Pair >
2021-01-12 21:28:56 +01:00
typename Pair : : second_type operator ( ) ( const Pair & p ) const {
2021-01-11 18:47:38 +01:00
return p . second ;
}
} ;
2021-10-04 07:53:58 +02:00
template < class Range , class T >
bool contains ( const Range & r , const T & x )
{
2022-12-30 15:13:47 +01:00
return std : : find ( r . cbegin ( ) , r . cend ( ) , x ) ! = r . cend ( ) ;
2021-10-04 07:53:58 +02:00
}
template < class T >
bool contains ( const std : : initializer_list < T > & r , const T & x )
{
return std : : find ( r . begin ( ) , r . end ( ) , x ) ! = r . end ( ) ;
}
template < class T , class U >
bool contains ( const std : : initializer_list < T > & r , const U & x )
{
return std : : find ( r . begin ( ) , r . end ( ) , x ) ! = r . end ( ) ;
}
2022-12-13 07:50:01 +01:00
template < class T , class . . . Ts >
inline std : : array < T , sizeof . . . ( Ts ) + 1 > makeArray ( T x , Ts . . . xs )
{
return { std : : move ( x ) , std : : move ( xs ) . . . } ;
}
2021-09-09 07:49:56 +02:00
// Enum hash for C++11. This is not needed in C++14
struct EnumClassHash {
template < typename T >
std : : size_t operator ( ) ( T t ) const
{
return static_cast < std : : size_t > ( t ) ;
}
} ;
2017-04-02 09:26:14 +02:00
inline bool endsWith ( const std : : string & str , char c )
{
2021-09-28 20:34:21 +02:00
return ! str . empty ( ) & & str . back ( ) = = c ;
2017-04-01 18:14:18 +02:00
}
2018-07-25 16:14:43 +02:00
inline bool endsWith ( const std : : string & str , const char end [ ] , std : : size_t endlen )
2017-04-23 10:17:35 +02:00
{
2018-07-25 16:14:43 +02:00
return ( str . size ( ) > = endlen ) & & ( str . compare ( str . size ( ) - endlen , endlen , end ) = = 0 ) ;
2017-04-23 10:17:35 +02:00
}
2021-09-28 20:34:21 +02:00
template < std : : size_t N >
bool endsWith ( const std : : string & str , const char ( & end ) [ N ] )
{
return endsWith ( str , end , N - 1 ) ;
}
2019-10-16 11:41:33 +02:00
inline static bool isPrefixStringCharLiteral ( const std : : string & str , char q , const std : : string & p )
{
2022-10-09 11:19:19 +02:00
// str must be at least the prefix plus the start and end quote
if ( str . length ( ) < p . length ( ) + 2 )
return false ;
// check for end quote
2019-10-16 11:41:33 +02:00
if ( ! endsWith ( str , q ) )
return false ;
2022-10-09 11:19:19 +02:00
// check for start quote
if ( str [ p . size ( ) ] ! = q )
return false ;
// check for prefix
if ( str . compare ( 0 , p . size ( ) , p ) ! = 0 )
return false ;
return true ;
2019-10-16 11:41:33 +02:00
}
inline static bool isStringCharLiteral ( const std : : string & str , char q )
{
2022-10-09 11:19:19 +02:00
// early out to avoid the loop
if ( ! endsWith ( str , q ) )
return false ;
2022-09-27 20:06:15 +02:00
static const std : : array < std : : string , 5 > suffixes { " " , " u8 " , " u " , " U " , " L " } ;
2022-12-30 15:13:47 +01:00
return std : : any_of ( suffixes . cbegin ( ) , suffixes . cend ( ) , [ & ] ( const std : : string & p ) {
2022-10-16 13:46:26 +02:00
return isPrefixStringCharLiteral ( str , q , p ) ;
} ) ;
2019-10-16 11:41:33 +02:00
}
inline static bool isStringLiteral ( const std : : string & str )
{
return isStringCharLiteral ( str , ' " ' ) ;
}
inline static bool isCharLiteral ( const std : : string & str )
{
return isStringCharLiteral ( str , ' \' ' ) ;
}
inline static std : : string getStringCharLiteral ( const std : : string & str , char q )
{
const std : : size_t quotePos = str . find ( q ) ;
return str . substr ( quotePos + 1U , str . size ( ) - quotePos - 2U ) ;
}
inline static std : : string getStringLiteral ( const std : : string & str )
{
if ( isStringLiteral ( str ) )
return getStringCharLiteral ( str , ' " ' ) ;
return " " ;
}
inline static std : : string getCharLiteral ( const std : : string & str )
{
if ( isCharLiteral ( str ) )
return getStringCharLiteral ( str , ' \' ' ) ;
return " " ;
}
2017-05-23 14:58:43 +02:00
inline static const char * getOrdinalText ( int i )
{
if ( i = = 1 )
return " st " ;
if ( i = = 2 )
return " nd " ;
if ( i = = 3 )
return " rd " ;
return " th " ;
}
2020-05-10 20:32:59 +02:00
CPPCHECKLIB int caseInsensitiveStringCompare ( const std : : string & lhs , const std : : string & rhs ) ;
2017-09-30 11:25:46 +02:00
2020-05-10 20:32:59 +02:00
CPPCHECKLIB bool isValidGlobPattern ( const std : : string & pattern ) ;
2020-01-24 07:06:09 +01:00
2020-05-10 20:32:59 +02:00
CPPCHECKLIB bool matchglob ( const std : : string & pattern , const std : : string & name ) ;
2020-01-24 07:06:09 +01:00
2021-11-23 22:51:45 +01:00
CPPCHECKLIB bool matchglobs ( const std : : vector < std : : string > & patterns , const std : : string & name ) ;
2022-04-15 16:17:36 +02:00
CPPCHECKLIB void strTolower ( std : : string & str ) ;
2023-04-08 22:29:09 +02:00
template < typename T , typename std : : enable_if < std : : is_signed < T > : : value , bool > : : type = true >
bool strToInt ( const std : : string & str , T & num , std : : string * err = nullptr )
{
long long tmp ;
try {
std : : size_t idx = 0 ;
tmp = std : : stoll ( str , & idx ) ;
if ( idx ! = str . size ( ) ) {
if ( err )
* err = " not an integer " ;
return false ;
}
} catch ( const std : : out_of_range & ) {
if ( err )
* err = " out of range (stoll) " ;
return false ;
} catch ( const std : : invalid_argument & ) {
if ( err )
* err = " not an integer " ;
return false ;
}
if ( str . front ( ) = = ' - ' & & std : : numeric_limits < T > : : min ( ) = = 0 ) {
if ( err )
* err = " needs to be positive " ;
return false ;
}
if ( tmp < std : : numeric_limits < T > : : min ( ) | | tmp > std : : numeric_limits < T > : : max ( ) ) {
if ( err )
* err = " out of range (limits) " ;
return false ;
}
num = static_cast < T > ( tmp ) ;
return true ;
}
template < typename T , typename std : : enable_if < std : : is_unsigned < T > : : value , bool > : : type = true >
bool strToInt ( const std : : string & str , T & num , std : : string * err = nullptr )
{
unsigned long long tmp ;
try {
std : : size_t idx = 0 ;
tmp = std : : stoull ( str , & idx ) ;
if ( idx ! = str . size ( ) ) {
if ( err )
* err = " not an integer " ;
return false ;
}
} catch ( const std : : out_of_range & ) {
if ( err )
* err = " out of range (stoull) " ;
return false ;
} catch ( const std : : invalid_argument & ) {
if ( err )
* err = " not an integer " ;
return false ;
}
if ( str . front ( ) = = ' - ' ) {
if ( err )
* err = " needs to be positive " ;
return false ;
}
if ( tmp > std : : numeric_limits < T > : : max ( ) ) {
if ( err )
* err = " out of range (limits) " ;
return false ;
}
num = tmp ;
return true ;
}
template < typename T >
T strToInt ( const std : : string & str )
{
T tmp = 0 ;
std : : string err ;
if ( ! strToInt ( str , tmp , & err ) )
throw std : : runtime_error ( " converting ' " + str + " ' to integer failed - " + err ) ;
return tmp ;
}
2022-08-16 22:03:44 +02:00
/**
* Simple helper function :
* \ return size of array
* */
template < typename T , int size >
2022-09-27 20:03:25 +02:00
std : : size_t getArrayLength ( const T ( & /*unused*/ ) [ size ] )
2022-08-16 22:03:44 +02:00
{
return size ;
}
2023-08-31 11:54:46 +02:00
/** this is meant as a replacement for when we cannot print a pointer via the stream insertion operator (operator<<) for performance reasons */
// TODO: should give portable value / only used by Tokenizer::dump() and underlying functions - something deterministic would also help with comparing the output
static inline std : : string ptr_to_string ( const void * p )
{
# if (defined(__APPLE__) && defined(__MACH__))
if ( p = = nullptr )
return " 0x0 " ;
# elif !defined(_WIN32) || defined(__MINGW32__)
if ( p = = nullptr )
return " 0 " ;
# endif
static constexpr int ptr_size = sizeof ( void * ) ;
# if defined(_WIN32) && !defined(__MINGW32__)
// two characters of each byte / contains terminating \0
static constexpr int buf_size = ( ptr_size * 2 ) + 1 ;
# else
// two characters of each byte / contains 0x prefix and contains terminating \0
static constexpr int buf_size = ( ptr_size * 2 ) + 2 + 1 ;
# endif
char buf [ buf_size ] ;
// needs to be signed so we don't underflow in padding loop
int idx = sizeof ( buf ) - 1 ;
buf [ idx - - ] = ' \0 ' ; // terminate string
uintptr_t l = reinterpret_cast < uintptr_t > ( p ) ;
while ( l ! = 0 )
{
char c ;
const uintptr_t temp = l % 16 ; // get the remainder
if ( temp < 10 ) {
// 0-9
c = ' 0 ' + temp ;
}
else {
# if !defined(_WIN32) || defined(__MINGW32__)
// a-f
c = ' a ' + ( temp - 10 ) ;
# else
// A-F
c = ' A ' + ( temp - 10 ) ;
# endif
}
buf [ idx - - ] = c ; // store in reverse order
l = l / 16 ;
}
# if defined(_WIN32) && !defined(__MINGW32__)
// pad address with 0
while ( idx > = 0 ) {
buf [ idx - - ] = ' 0 ' ;
}
// 000000F0A61FF122 or 0230FB33
return buf ;
# else
// add 0x prefix
buf [ idx - - ] = ' x ' ;
buf [ idx - - ] = ' 0 ' ;
// 0x7ffc5aa334d8
return & buf [ idx + 1 ] ;
# endif
}
static inline std : : string bool_to_string ( bool b )
{
return b ? " true " : " false " ;
}
2015-06-20 22:26:51 +02:00
# endif