46 #include <immintrin.h>
56 bool contains_ci( std::vector<std::string>
const& haystack, std::string
const& needle )
58 auto const l_needle =
to_lower( needle );
59 for(
auto const& val : haystack ) {
67 bool equals_ci( std::string
const& lhs, std::string
const& rhs)
69 const size_t sz = lhs.size();
70 if( rhs.size() != sz ) {
73 for(
size_t i = 0; i < sz; ++i ) {
74 if( tolower( lhs[i] ) != tolower( rhs[i] ) ) {
81 bool starts_with( std::string
const & text, std::string
const & start )
83 if (start.size() > text.size()) {
86 return std::equal( start.begin(), start.end(), text.begin() );
89 bool ends_with( std::string
const & text, std::string
const & ending )
91 if (ending.size() > text.size()) {
94 return std::equal( ending.rbegin(), ending.rend(), text.rbegin() );
102 if( pattern.empty() ) {
108 auto lookup_ = std::vector<bool>(( str.size() + 1 ) * ( pattern.size() + 1 ),
false);
109 auto lookup = [&](
size_t i,
size_t j ) -> std::vector<bool>::reference {
110 return lookup_[ i * ( pattern.size() + 1 ) + j ];
114 lookup( 0, 0 ) =
true;
117 for(
size_t j = 1; j <= pattern.size(); j++ ) {
118 if( pattern[j - 1] ==
'*' ) {
119 lookup( 0, j ) = lookup( 0, j - 1 );
124 for(
size_t i = 1; i <= str.size(); i++ ) {
125 for(
size_t j = 1; j <= pattern.size(); j++ ) {
126 if( pattern[j - 1] ==
'*' ) {
132 lookup( i, j ) = lookup( i, j - 1 ) || lookup( i - 1, j );
134 }
else if( pattern[j - 1] ==
'?' || str[i - 1] == pattern[j - 1] )
139 lookup( i, j ) = lookup( i - 1, j - 1 );
144 lookup( i, j ) =
false;
149 return lookup( str.size(), pattern.size() );
159 if( lhs.empty() || rhs.empty() ) {
164 return static_cast<int>( rhs.empty() ) -
static_cast<int>( lhs.empty() );
173 auto mode = ParseMode::kString;
196 while( l < lhs.size() && r < rhs.size() ) {
197 if( mode == ParseMode::kString ) {
200 while( l < lhs.size() && r < rhs.size() ) {
203 bool const l_digit =
is_digit( lhs[l] );
204 bool const r_digit =
is_digit( rhs[r] );
207 if( l_digit && r_digit ) {
208 mode = ParseMode::kNumber;
221 assert( ! l_digit && ! r_digit );
222 int const diff =
static_cast<int>( lhs[l] ) -
static_cast<int>( rhs[r] );
233 assert( mode == ParseMode::kNumber );
244 while( ld < lhs.size() &&
is_digit( lhs[ld] )) {
247 while( rd < rhs.size() &&
is_digit( rhs[rd] )) {
254 return static_cast<int>( ld ) -
static_cast<int>( rd );
259 while( l < lhs.size() && r < rhs.size() ) {
262 bool const l_digit =
is_digit( lhs[l] );
263 bool const r_digit =
is_digit( rhs[r] );
266 if( ! l_digit || ! r_digit ) {
269 assert( ! l_digit && ! r_digit );
270 assert( ld == rd && l == ld && r == rd );
271 mode = ParseMode::kString;
276 assert( l_digit && r_digit );
277 int const diff =
static_cast<int>( lhs[l] ) -
static_cast<int>( rhs[r] );
291 if( l < lhs.size() ) {
292 assert( r == rhs.size() );
295 if( r < rhs.size() ) {
296 assert( l == lhs.size() );
299 assert( l == lhs.size() && r == rhs.size() );
307 std::string
head( std::string
const& text,
size_t lines )
310 auto vec =
split( text,
"\n",
false );
311 size_t remove = vec.size() > lines ? vec.size() - lines : 0;
312 vec.erase( vec.end() - remove, vec.end() );
313 return join( vec,
"\n" );
316 std::string
tail( std::string
const& text,
size_t lines )
319 auto vec =
split( text,
"\n",
false );
320 size_t remove = vec.size() > lines ? vec.size() - lines : 0;
321 vec.erase( vec.begin(), vec.begin() + remove );
322 return join( vec,
"\n" );
331 if (sub.length() == 0) {
337 size_t offset = str.find(sub);
338 offset != std::string::npos;
351 std::string
const&
string,
352 std::function<
size_t ( std::string
const&,
size_t )> find_pos,
354 const bool trim_empty
356 std::vector<std::string> result;
361 size_t pos = find_pos(
string, last_pos );
364 if( pos == std::string::npos ) {
365 pos =
string.length();
367 if( pos != last_pos || !trim_empty ) {
368 result.push_back( std::string(
string.data() + last_pos, pos - last_pos ));
375 if( pos != last_pos || !trim_empty ) {
376 result.push_back( std::string(
string.data() + last_pos, pos - last_pos ));
380 last_pos = pos + advance_by;
387 std::string
const& str,
388 std::string
const& delimiters,
389 const bool trim_empty
393 [&]( std::string
const& str,
size_t last_pos ){
394 return str.find_first_of( delimiters, last_pos );
402 std::string
const& str,
403 std::function<
bool(
char)> delimiter_predicate,
404 const bool trim_empty
408 [&]( std::string
const& str,
size_t last_pos ){
410 size_t pos = std::string::npos;
411 for(
size_t i = last_pos; i < str.size(); ++i ) {
412 if( delimiter_predicate( str[i] ) ) {
425 std::string
const& str,
426 std::string
const& delimiter,
427 const bool trim_empty
431 [&]( std::string
const& str,
size_t last_pos ){
432 return str.find( delimiter, last_pos );
441 std::vector<size_t> result;
443 auto is_digits = []( std::string
const& s ){
444 return trim( s ).find_first_not_of(
"0123456789" ) == std::string::npos;
447 auto get_number = []( std::string
const& s ){
449 sscanf(
trim( s ).c_str(),
"%zu", &n );
453 if(
trim( str ).empty() ) {
457 auto const lst =
split( str,
"," );
458 for(
auto const& le : lst ) {
460 if( is_digits( le ) ) {
461 result.push_back( get_number( le ));
463 auto const rng =
split( le,
"-" );
464 if( rng.size() != 2 || ! is_digits( rng[0] ) || ! is_digits( rng[1] ) ) {
465 throw std::runtime_error(
"Invalid range list string." );
467 auto const b = get_number( rng[0] );
468 auto const e = get_number( rng[1] );
469 for(
size_t i = b; i <= e; ++i ) {
470 result.push_back( i );
475 std::sort( result.begin(), result.end() );
484 std::string
const& text,
497 std::ostringstream output;
498 auto const lines =
split( text,
"\n",
false );
499 for(
auto const& line : lines ) {
500 std::istringstream text_stream( line );
503 if( text_stream >> word ) {
505 long space_left =
static_cast<long>( line_length ) -
static_cast<long>( word.length() );
506 while( text_stream >> word ) {
507 if( space_left <
static_cast<long>( word.length() + 1 )) {
508 output <<
"\n" << word;
509 space_left = line_length - word.length();
511 output <<
" " << word;
512 space_left -= word.length() + 1;
523 std::string
const& text,
524 std::string
const& indentation
526 auto ret = indentation +
replace_all( text,
"\n",
"\n" + indentation );
531 std::string
const& text, std::string
const& search, std::string
const& replace
533 std::string tmp = text;
534 for (
size_t pos = 0; ; pos += replace.length()) {
535 pos = tmp.find(search, pos);
537 if (pos == std::string::npos){
541 tmp.erase(pos, search.length());
542 tmp.insert(pos, replace);
565 std::string
const& text,
566 std::string
const& search_chars,
570 for(
auto& c : result ) {
571 if( search_chars.find( c ) != std::string::npos ) {
579 std::string
const& s,
580 std::string
const& delimiters
582 auto const pos = s.find_last_not_of(delimiters);
583 if( std::string::npos == pos ) {
586 return s.substr( 0, pos + 1 );
591 std::string
const& s,
592 std::string
const& delimiters
594 auto const pos = s.find_first_not_of(delimiters);
595 if( std::string::npos == pos ) {
598 return s.substr(pos);
603 std::string
const& s,
604 std::string
const& delimiters
615 inline void toggle_case_ascii_inplace_avx_( std::string& str,
char char_a,
char char_z )
622 auto static const val_32 = _mm256_set1_epi8( 0x20 );
625 auto const mask_a = _mm256_set1_epi8( char_a );
626 auto const mask_z = _mm256_set1_epi8( char_z );
629 for(
size_t i = 0; i < str.size() / 32 * 32; i += 32 ) {
630 auto reg = _mm256_loadu_si256(
reinterpret_cast<__m256i*
>( &str[i] ) );
633 auto mask_az = _mm256_or_si256( _mm256_cmpgt_epi8( mask_a, reg ), _mm256_cmpgt_epi8( reg, mask_z ) );
636 reg = _mm256_xor_si256( _mm256_andnot_si256( mask_az, val_32 ), reg );
638 _mm256_storeu_si256(
reinterpret_cast<__m256i*
>( &str[i] ), reg );
642 for(
size_t i = str.size() / 32 * 32; i < str.size(); ++i ) {
643 if( char_a <= str[i] && str[i] <= char_z ){
649 #endif // GENESIS_AVX
656 toggle_case_ascii_inplace_avx_( str,
'A',
'Z' );
661 for(
auto& c : str ){
665 #endif // GENESIS_AVX
680 toggle_case_ascii_inplace_avx_( str,
'a',
'z' );
685 for(
auto& c : str ){
689 #endif // GENESIS_AVX
703 std::string
escape( std::string
const& text )
719 tmp.reserve( text.size() );
722 for(
size_t i = 0; i < text.size(); ++i ) {
723 if( text[ i ] ==
'\\' ) {
724 if( i + 1 >= text.size() ){
758 std::string
repeat( std::string
const& word,
size_t times )
762 result.reserve( times * word.length() );
765 for(
size_t i = 0; i < times; ++i ) {
773 std::stringstream ss;
774 ss << std::setw(
length ) << std::setfill(
'0' ) << value;
781 std::ostringstream s;
782 s << std::fixed << std::setprecision( precision ) << value;
789 std::ostringstream s;
790 s << std::fixed << std::setprecision( precision ) << value;
796 size_t const last_nonzero = str.find_last_not_of(
'0');
797 if( str[ last_nonzero ] ==
'.' ) {
800 str.erase( last_nonzero +
offset, std::string::npos );