46 #if defined(GENESIS_AVX) || defined(GENESIS_AVX2) || defined(GENESIS_AVX512)
48 #include <immintrin.h>
59 bool contains_ci( std::vector<std::string>
const& haystack, std::string
const& needle )
62 auto const l_needle =
to_lower( needle );
63 for(
auto const& val : haystack ) {
71 bool contains_ci_alnum( std::vector<std::string>
const& haystack, std::string
const& needle )
75 for(
auto const& val : haystack ) {
77 if(
equals_ci( alnum_val, lower_alnum_needle )) {
87 return strncasecmp( s1, s2, std::numeric_limits<size_t>::max() );
98 auto ucs1 =
reinterpret_cast<unsigned char const*
>( s1 );
99 auto ucs2 =
reinterpret_cast<unsigned char const*
>( s2 );
103 for( ; n != 0; n-- ) {
104 int const c1 = tolower( *ucs1++ );
105 int const c2 = tolower( *ucs2++ );
107 if(( d != 0 ) || ( c1 ==
'\0' )) {
114 bool equals_ci( std::string
const& lhs, std::string
const& rhs)
116 const size_t sz = lhs.size();
117 if( rhs.size() != sz ) {
120 for(
size_t i = 0; i < sz; ++i ) {
121 if( tolower( lhs[i] ) != tolower( rhs[i] ) ) {
133 return equals_ci( alnum_lhs, alnum_rhs );
136 bool starts_with( std::string
const& text, std::string
const& prefix )
138 if( prefix.size() > text.size() ) {
141 return std::equal( prefix.begin(), prefix.end(), text.begin() );
144 bool starts_with( std::string
const& text, std::string
const& prefix, std::string& suffix )
148 assert( prefix.size() <= text.size() );
149 suffix = text.substr( prefix.size() );
160 bool starts_with_ci( std::string
const& text, std::string
const& prefix, std::string& suffix )
164 assert( prefix.size() <= text.size() );
165 suffix = text.substr( prefix.size() );
178 std::string
const& text, std::string
const& prefix, std::string& suffix,
bool trim_suffix
186 while( p < prefix.size() && t < text.size() ) {
205 assert( p <= prefix.size() );
206 assert( t <= text.size() );
210 if( t == text.size() ) {
217 assert( t < text.size() );
218 assert( p == prefix.size() );
221 while( trim_suffix && t < text.size() && !
is_alnum(text[t]) ) {
226 suffix = text.substr(t);
230 bool ends_with( std::string
const& text, std::string
const& suffix )
232 if( suffix.size() > text.size() ) {
235 return std::equal( suffix.rbegin(), suffix.rend(), text.rbegin() );
238 bool ends_with( std::string
const& text, std::string
const& suffix, std::string& prefix )
240 auto const res =
ends_with( text, suffix );
242 assert( suffix.size() <= text.size() );
243 prefix = text.substr( 0, text.size() - suffix.size() );
248 bool ends_with_ci( std::string
const& text, std::string
const& suffix )
254 bool ends_with_ci( std::string
const& text, std::string
const& suffix, std::string& prefix )
258 assert( suffix.size() <= text.size() );
259 prefix = text.substr( 0, text.size() - suffix.size() );
272 std::string
const& text, std::string
const& suffix, std::string& prefix,
bool trim_prefix
276 auto const text_r = std::string( text.rbegin(), text.rend() );
277 auto const suffix_r = std::string( suffix.rbegin(), suffix.rend() );
280 prefix = std::string( prefix.rbegin(), prefix.rend() );
291 if( pattern.empty() ) {
297 auto lookup_ = std::vector<bool>(( str.size() + 1 ) * ( pattern.size() + 1 ),
false);
298 auto lookup = [&](
size_t i,
size_t j ) -> std::vector<bool>::reference {
299 return lookup_[ i * ( pattern.size() + 1 ) + j ];
303 lookup( 0, 0 ) =
true;
306 for(
size_t j = 1; j <= pattern.size(); j++ ) {
307 if( pattern[j - 1] ==
'*' ) {
308 lookup( 0, j ) = lookup( 0, j - 1 );
313 for(
size_t i = 1; i <= str.size(); i++ ) {
314 for(
size_t j = 1; j <= pattern.size(); j++ ) {
315 if( pattern[j - 1] ==
'*' ) {
321 lookup( i, j ) = lookup( i, j - 1 ) || lookup( i - 1, j );
323 }
else if( pattern[j - 1] ==
'?' || str[i - 1] == pattern[j - 1] )
328 lookup( i, j ) = lookup( i - 1, j - 1 );
333 lookup( i, j ) =
false;
338 return lookup( str.size(), pattern.size() );
348 if( lhs.empty() || rhs.empty() ) {
353 return static_cast<int>( rhs.empty() ) -
static_cast<int>( lhs.empty() );
362 auto mode = ParseMode::kString;
385 while( l < lhs.size() && r < rhs.size() ) {
386 if( mode == ParseMode::kString ) {
389 while( l < lhs.size() && r < rhs.size() ) {
392 bool const l_digit =
is_digit( lhs[l] );
393 bool const r_digit =
is_digit( rhs[r] );
396 if( l_digit && r_digit ) {
397 mode = ParseMode::kNumber;
410 assert( ! l_digit && ! r_digit );
411 int const diff =
static_cast<int>( lhs[l] ) -
static_cast<int>( rhs[r] );
422 assert( mode == ParseMode::kNumber );
433 while( ld < lhs.size() &&
is_digit( lhs[ld] )) {
436 while( rd < rhs.size() &&
is_digit( rhs[rd] )) {
443 return static_cast<int>( ld ) -
static_cast<int>( rd );
448 while( l < lhs.size() && r < rhs.size() ) {
451 bool const l_digit =
is_digit( lhs[l] );
452 bool const r_digit =
is_digit( rhs[r] );
455 if( ! l_digit || ! r_digit ) {
458 assert( ! l_digit && ! r_digit );
459 assert( ld == rd && l == ld && r == rd );
460 mode = ParseMode::kString;
465 assert( l_digit && r_digit );
466 int const diff =
static_cast<int>( lhs[l] ) -
static_cast<int>( rhs[r] );
480 if( l < lhs.size() ) {
481 assert( r == rhs.size() );
484 if( r < rhs.size() ) {
485 assert( l == lhs.size() );
488 assert( l == lhs.size() && r == rhs.size() );
496 std::string
head( std::string
const& text,
size_t lines )
499 auto vec =
split( text,
"\n",
false );
500 size_t remove = vec.size() > lines ? vec.size() - lines : 0;
501 vec.erase( vec.end() - remove, vec.end() );
502 return join( vec,
"\n" );
505 std::string
tail( std::string
const& text,
size_t lines )
508 auto vec =
split( text,
"\n",
false );
509 size_t remove = vec.size() > lines ? vec.size() - lines : 0;
510 vec.erase( vec.begin(), vec.begin() + remove );
511 return join( vec,
"\n" );
520 if (sub.length() == 0) {
526 size_t offset = str.find(sub);
527 offset != std::string::npos;
540 std::string
const&
string,
541 std::function<
size_t ( std::string
const&,
size_t )> find_pos,
543 const bool trim_empty
545 std::vector<std::string> result;
550 size_t pos = find_pos(
string, last_pos );
553 if( pos == std::string::npos ) {
554 pos =
string.length();
556 if( pos != last_pos || !trim_empty ) {
557 result.push_back( std::string(
string.data() + last_pos, pos - last_pos ));
564 if( pos != last_pos || !trim_empty ) {
565 result.push_back( std::string(
string.data() + last_pos, pos - last_pos ));
569 last_pos = pos + advance_by;
576 std::string
const& str,
578 const bool trim_empty
580 return split( str, std::string( 1, delimiter ), trim_empty );
584 std::string
const& str,
585 std::string
const& delimiters,
586 const bool trim_empty
590 [&]( std::string
const& str,
size_t last_pos ){
591 return str.find_first_of( delimiters, last_pos );
599 std::string
const& str,
600 std::function<
bool(
char)> delimiter_predicate,
601 const bool trim_empty
605 [&]( std::string
const& str,
size_t last_pos ){
607 size_t pos = std::string::npos;
608 for(
size_t i = last_pos; i < str.size(); ++i ) {
609 if( delimiter_predicate( str[i] ) ) {
622 std::string
const& str,
623 std::string
const& delimiter,
624 const bool trim_empty
628 [&]( std::string
const& str,
size_t last_pos ){
629 return str.find( delimiter, last_pos );
638 std::vector<size_t> result;
640 auto is_digits = []( std::string
const& s ){
641 return trim( s ).find_first_not_of(
"0123456789" ) == std::string::npos;
644 auto get_number = []( std::string
const& s ){
646 sscanf(
trim( s ).c_str(),
"%zu", &n );
650 if(
trim( str ).empty() ) {
654 auto const lst =
split( str,
"," );
655 for(
auto const& le : lst ) {
657 if( is_digits( le ) ) {
658 result.push_back( get_number( le ));
660 auto const rng =
split( le,
"-" );
661 if( rng.size() != 2 || ! is_digits( rng[0] ) || ! is_digits( rng[1] ) ) {
662 throw std::runtime_error(
"Invalid range list string." );
664 auto const b = get_number( rng[0] );
665 auto const e = get_number( rng[1] );
666 for(
size_t i = b; i <= e; ++i ) {
667 result.push_back( i );
672 std::sort( result.begin(), result.end() );
681 std::string
const& text,
694 std::ostringstream output;
695 auto const lines =
split( text,
"\n",
false );
696 for(
auto const& line : lines ) {
697 std::istringstream text_stream( line );
700 if( text_stream >> word ) {
702 long space_left =
static_cast<long>( line_length ) -
static_cast<long>( word.length() );
703 while( text_stream >> word ) {
704 if( space_left <
static_cast<long>( word.length() + 1 )) {
705 output <<
"\n" << word;
706 space_left = line_length - word.length();
708 output <<
" " << word;
709 space_left -= word.length() + 1;
720 std::string
const& text,
721 std::string
const& indentation
723 auto ret = indentation +
replace_all( text,
"\n",
"\n" + indentation );
728 std::string
const& text, std::string
const& search, std::string
const& replace
730 std::string tmp = text;
731 for (
size_t pos = 0; ; pos += replace.length()) {
732 pos = tmp.find(search, pos);
734 if (pos == std::string::npos){
738 tmp.erase(pos, search.length());
739 tmp.insert(pos, replace);
762 std::string
const& text,
763 std::string
const& search
769 std::string
const& text,
770 std::string
const& search_chars,
774 for(
auto& c : result ) {
775 if( search_chars.find( c ) != std::string::npos ) {
783 std::string
const& text,
784 std::string
const& search_chars
788 for(
size_t i = 0; i < search_chars.length(); ++i ) {
789 result.erase( std::remove( result.begin(), result.end(), search_chars[i] ), result.end() );
804 std::string
const& s,
805 std::string
const& delimiters
807 auto const pos = s.find_last_not_of(delimiters);
808 if( std::string::npos == pos ) {
811 return s.substr( 0, pos + 1 );
816 std::string
const& s,
817 std::string
const& delimiters
819 auto const pos = s.find_first_not_of(delimiters);
820 if( std::string::npos == pos ) {
823 return s.substr(pos);
828 std::string
const& s,
829 std::string
const& delimiters
840 inline void toggle_case_ascii_inplace_avx_( std::string& str,
char char_a,
char char_z )
847 auto static const val_32 = _mm256_set1_epi8( 0x20 );
850 auto const mask_a = _mm256_set1_epi8( char_a );
851 auto const mask_z = _mm256_set1_epi8( char_z );
854 for(
size_t i = 0; i < str.size() / 32 * 32; i += 32 ) {
855 auto reg = _mm256_loadu_si256(
reinterpret_cast<__m256i*
>( &str[i] ) );
858 auto mask_az = _mm256_or_si256(
859 _mm256_cmpgt_epi8( mask_a, reg ), _mm256_cmpgt_epi8( reg, mask_z )
863 reg = _mm256_xor_si256( _mm256_andnot_si256( mask_az, val_32 ), reg );
865 _mm256_storeu_si256(
reinterpret_cast<__m256i*
>( &str[i] ), reg );
869 for(
size_t i = str.size() / 32 * 32; i < str.size(); ++i ) {
870 if( char_a <= str[i] && str[i] <= char_z ){
876 #endif // GENESIS_AVX2
883 toggle_case_ascii_inplace_avx_( str,
'A',
'Z' );
885 #else // GENESIS_AVX2
888 for(
auto& c : str ){
892 #endif // GENESIS_AVX2
907 toggle_case_ascii_inplace_avx_( str,
'a',
'z' );
909 #else // GENESIS_AVX2
912 for(
auto& c : str ){
916 #endif // GENESIS_AVX2
930 std::string
escape( std::string
const& text )
932 static_assert( CHAR_BIT == 8,
"CHAR_BIT != 8" );
934 for(
auto c : text ) {
935 if(
' ' <= c && c <=
'~' && c !=
'\\' && c !=
'"') {
940 case '"': tmp +=
'"';
break;
941 case '\\': tmp +=
'\\';
break;
942 case '\t': tmp +=
't';
break;
943 case '\r': tmp +=
'r';
break;
944 case '\n': tmp +=
'n';
break;
947 char const*
const hexdig =
"0123456789ABCDEF";
949 tmp += hexdig[c >> 4];
950 tmp += hexdig[c & 0xF];
962 tmp.reserve( text.size() );
965 for(
size_t i = 0; i < text.size(); ++i ) {
966 if( text[ i ] ==
'\\' ) {
967 if( i + 1 >= text.size() ){
1001 std::string
repeat( std::string
const& word,
size_t times )
1005 result.reserve( times * word.length() );
1008 for(
size_t i = 0; i < times; ++i ) {
1016 std::stringstream ss;
1017 ss << std::setw(
length ) << std::setfill(
'0' ) << value;
1024 std::ostringstream s;
1025 s << std::fixed << std::setprecision( precision ) << value;
1032 std::ostringstream s;
1033 s << std::fixed << std::setprecision( precision ) << value;
1039 size_t const last_nonzero = str.find_last_not_of(
'0');
1040 if( str[ last_nonzero ] ==
'.' ) {
1043 str.erase( last_nonzero +
offset, std::string::npos );
1049 const char* suffixes[] = {
"B",
"KB",
"MB",
"GB",
"TB",
"PB",
"EB"};
1050 size_t magnitude = 0;
1051 double size =
static_cast<double>(value);
1054 while( size >= 1024 && magnitude < (
sizeof(suffixes) /
sizeof(suffixes[0])) - 1 ) {
1059 std::ostringstream oss;
1060 oss << std::fixed << std::setprecision(2) << size << suffixes[magnitude];