@@ -366,6 +366,14 @@ void ExprCompiler::operator()(const ast::BinaryExpr &e)
366
366
set (like_contains (str, pattern));
367
367
break ;
368
368
}
369
+ if (std::regex_match (*pattern, std::regex (" [^_%\\\\ ]+%" ))) { // prefix expression
370
+ set (like_prefix (str, pattern));
371
+ break ;
372
+ }
373
+ if (std::regex_match (*pattern, std::regex (" %[^_%\\\\ ]+" ))) { // suffix expression
374
+ set (like_suffix (str, pattern));
375
+ break ;
376
+ }
369
377
}
370
378
/* no specialization applicable, fallback to general dynamic programming approach */
371
379
(*this )(*e.rhs );
@@ -3624,6 +3632,60 @@ _Boolx1 m::wasm::like_contains(NChar _str, const ThreadSafePooledString &_patter
3624
3632
}
3625
3633
}
3626
3634
3635
+ _Boolx1 m::wasm::like_prefix (NChar str, const ThreadSafePooledString &pattern)
3636
+ {
3637
+ M_insist (std::regex_match (*pattern, std::regex (" [^_%\\\\ ]+%" )), " invalid prefix pattern" );
3638
+
3639
+ /* ----- Create lower bound. -----*/
3640
+ const int32_t len_pattern = strlen (*pattern) - 1 ; // minus 1 due to ending `%`
3641
+ auto _lower_bound = Module::Allocator ().raw_malloc <char >(len_pattern + 1 );
3642
+ for (std::size_t i = 0 ; i < len_pattern; ++i)
3643
+ _lower_bound[i] = (*pattern)[i];
3644
+ _lower_bound[len_pattern] = ' \0 ' ;
3645
+ NChar lower_bound (Ptr<Charx1>(_lower_bound), false , len_pattern, true );
3646
+
3647
+ /* ----- Create upper bound. -----*/
3648
+ auto _upper_bound = Module::Allocator ().raw_malloc <char >(len_pattern + 1 );
3649
+ for (std::size_t i = 0 ; i < len_pattern - 1 ; ++i)
3650
+ _upper_bound[i] = (*pattern)[i];
3651
+ const char last_char = (*pattern)[len_pattern - 1 ];
3652
+ _upper_bound[len_pattern - 1 ] = last_char + 1 ; // increment last character for upper bound
3653
+ _upper_bound[len_pattern] = ' \0 ' ;
3654
+ NChar upper_bound (Ptr<Charx1>(_upper_bound), false , len_pattern, true );
3655
+
3656
+ /* ----- Compute result by checking whether given string is in created interval. -----*/
3657
+ auto str_cpy = str.clone ();
3658
+ return strcmp (str_cpy, lower_bound, GE) and strcmp (str, upper_bound, LT);
3659
+ }
3660
+
3661
+ _Boolx1 m::wasm::like_suffix (NChar str, const ThreadSafePooledString &pattern)
3662
+ {
3663
+ M_insist (std::regex_match (*pattern, std::regex (" %[^_%\\\\ ]+" )), " invalid suffix pattern" );
3664
+
3665
+ /* ----- Create lower bound. -----*/
3666
+ const int32_t len_pattern = strlen (*pattern) - 1 ; // minus 1 due to starting `%`
3667
+ auto _lower_bound = Module::Allocator ().raw_malloc <char >(len_pattern + 1 );
3668
+ for (std::size_t i = 0 ; i < len_pattern; ++i)
3669
+ _lower_bound[i] = (*pattern)[i + 1 ]; // access pattern with offset +1 due to starting `%`
3670
+ _lower_bound[len_pattern] = ' \0 ' ;
3671
+ NChar lower_bound (Ptr<Charx1>(_lower_bound), false , len_pattern, true );
3672
+
3673
+ /* ----- Create upper bound. -----*/
3674
+ auto _upper_bound = Module::Allocator ().raw_malloc <char >(len_pattern + 1 );
3675
+ const char first_char = (*pattern)[1 ]; // access first character at offset 1 due to starting `%`
3676
+ _upper_bound[0 ] = first_char + 1 ; // increment first character for upper bound
3677
+ for (std::size_t i = 1 ; i < len_pattern; ++i)
3678
+ _upper_bound[i] = (*pattern)[i + 1 ]; // access pattern with offset +1 due to starting `%`
3679
+ _upper_bound[len_pattern] = ' \0 ' ;
3680
+ NChar upper_bound (Ptr<Charx1>(_upper_bound), false , len_pattern, true );
3681
+
3682
+ /* ----- Compute result by checking whether given string is in created interval when reversed. -----*/
3683
+ const auto max_length = std::max<uint32_t >(str.length (), len_pattern); // use maximal length due to reversed strncmp
3684
+ auto str_cpy = str.clone ();
3685
+ return strncmp (str_cpy, lower_bound, U32x1 (max_length), GE, true ) and
3686
+ strncmp (str, upper_bound, U32x1 (max_length), LT, true );
3687
+ }
3688
+
3627
3689
3628
3690
/* ======================================================================================================================
3629
3691
* comparator
0 commit comments