diff --git a/runtime-common/stdlib/string/string-functions.cpp b/runtime-common/stdlib/string/string-functions.cpp index 86eb5b8c4..892c5e448 100644 --- a/runtime-common/stdlib/string/string-functions.cpp +++ b/runtime-common/stdlib/string/string-functions.cpp @@ -105,26 +105,6 @@ string f$addslashes(const string &str) noexcept { return kphp_runtime_context.static_SB.str(); } -string f$bin2hex(const string &str) noexcept { - int len = str.size(); - string result(2 * len, false); - - for (int i = 0; i < len; i++) { - result[2 * i] = StringLibConstants::get().lhex_digits[(str[i] >> 4) & 15]; - result[2 * i + 1] = StringLibConstants::get().lhex_digits[str[i] & 15]; - } - - return result; -} - -string f$chop(const string &s, const string &what) noexcept { - return f$rtrim(s, what); -} - -string f$chr(int64_t v) noexcept { - return {1, static_cast(v)}; -} - constexpr unsigned char win_to_koi[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, @@ -519,19 +499,6 @@ string f$htmlspecialchars_decode(const string &str, int64_t flags) noexcept { return res; } -string f$lcfirst(const string &str) noexcept { - int n = str.size(); - if (n == 0) { - return str; - } - - string res(n, false); - res[0] = static_cast(tolower(str[0])); - memcpy(&res[1], &str[1], n - 1); - - return res; -} - int64_t f$levenshtein(const string &str1, const string &str2) noexcept { string::size_type len1 = str1.size(); string::size_type len2 = str2.size(); @@ -573,21 +540,6 @@ int64_t f$levenshtein(const string &str1, const string &str2) noexcept { return dp[len1 & 1][len2]; } -string f$ltrim(const string &s, const string &what) noexcept { - const char *mask = get_mask(what); - - int len = static_cast(s.size()); - if (len == 0 || !mask[static_cast(s[0])]) { - return s; - } - - int l = 1; - while (l < len && mask[static_cast(s[l])]) { - l++; - } - return {s.c_str() + l, static_cast(len - l)}; -} - string f$mysql_escape_string(const string &str) noexcept { int len = str.size(); kphp_runtime_context.static_SB.clean().reserve(2 * len); @@ -702,10 +654,6 @@ string f$number_format(double number, int64_t decimals, const string &dec_point, return {result_begin, static_cast(StringLibContext::get().static_buf.data() + StringLibContext::STATIC_BUFFER_LENGTH - result_begin)}; } -int64_t f$ord(const string &s) noexcept { - return static_cast(s[0]); -} - static uint64_t float64_bits(double f) { uint64_t bits = 0; std::memcpy(&bits, &f, sizeof(uint64_t)); @@ -923,6 +871,21 @@ string f$prepare_search_query(const string &query) noexcept { return string(s); } +string f$ltrim(const string &s, const string &what) noexcept { + const char *mask = get_mask(what); + + int len = static_cast(s.size()); + if (len == 0 || !mask[static_cast(s[0])]) { + return s; + } + + int l = 1; + while (l < len && mask[static_cast(s[l])]) { + l++; + } + return {s.c_str() + l, static_cast(len - l)}; +} + string f$rtrim(const string &s, const string &what) noexcept { const char *mask = get_mask(what); @@ -938,18 +901,6 @@ string f$rtrim(const string &s, const string &what) noexcept { return {s.c_str(), static_cast(len)}; } -Optional f$setlocale(int64_t category, const string &locale) noexcept { - const char *loc = locale.c_str(); - if (locale[0] == '0' && locale.size() == 1) { - loc = nullptr; - } - char *res = setlocale(static_cast(category), loc); - if (res == nullptr) { - return false; - } - return string(res); -} - string f$sprintf(const string &format, const array &a) noexcept { string result; result.reserve_at_least(format.size()); @@ -1287,22 +1238,6 @@ string f$stripslashes(const string &str) noexcept { return result; } -int64_t f$strcasecmp(const string &lhs, const string &rhs) noexcept { - int n = min(lhs.size(), rhs.size()); - for (int i = 0; i < n; i++) { - if (tolower(lhs[i]) != tolower(rhs[i])) { - return tolower(lhs[i]) - tolower(rhs[i]); - } - } - // TODO: for PHP8.2, use <=> operator instead: - // return spaceship(static_cast(lhs.size()), static_cast(rhs.size())); - return static_cast(lhs.size()) - static_cast(rhs.size()); -} - -int64_t f$strcmp(const string &lhs, const string &rhs) noexcept { - return lhs.compare(rhs); -} - Optional f$stripos(const string &haystack, const string &needle, int64_t offset) noexcept { if (offset < 0) { php_warning("Wrong offset = %" PRIi64 " in function stripos", offset); @@ -1567,15 +1502,6 @@ string strip_tags_string(const array &list) { return allow_str; } -string f$strip_tags(const string &str, const array &allow_list) noexcept { - php_assert(allow_list.empty()); - return f$strip_tags(str, string()); -} - -string f$strip_tags(const string &str, const array &allow_list) { - return f$strip_tags(str, strip_tags_string(allow_list)); -} - string f$strip_tags(const string &str, const mixed &allow) { if (!allow.is_array()) { return f$strip_tags(str, allow.to_string()); @@ -1584,6 +1510,10 @@ string f$strip_tags(const string &str, const mixed &allow) { return f$strip_tags(str, strip_tags_string(allow_list)); } +string f$strip_tags(const string &str, const array &allow_list) { + return f$strip_tags(str, strip_tags_string(allow_list)); +} + Optional f$stristr(const string &haystack, const string &needle, bool before_needle) noexcept { if (static_cast(needle.size()) == 0) { php_warning("Parameter needle is empty in function stristr"); @@ -1619,13 +1549,6 @@ Optional f$strrchr(const string &haystack, const string &needle) noexcep return false; } -int64_t f$strncmp(const string &lhs, const string &rhs, int64_t len) noexcept { - if (len < 0) { - return 0; - } - return memcmp(lhs.c_str(), rhs.c_str(), min(int64_t{min(lhs.size(), rhs.size())} + 1, len)); -} - /* Modified for PHP by Andrei Zmievski Modified for KPHP by Niyaz Nigmatullin @@ -1794,23 +1717,6 @@ int64_t f$strnatcmp(const string &lhs, const string &rhs) noexcept { return strnatcmp_ex(lhs.c_str(), lhs.size(), rhs.c_str(), rhs.size(), 0); } -int64_t f$strspn(const string &hayshack, const string &char_list, int64_t offset) noexcept { - return strspn(hayshack.c_str() + hayshack.get_correct_offset_clamped(offset), char_list.c_str()); -} - -int64_t f$strcspn(const string &hayshack, const string &char_list, int64_t offset) noexcept { - return strcspn(hayshack.c_str() + hayshack.get_correct_offset_clamped(offset), char_list.c_str()); -} - -Optional f$strpbrk(const string &haystack, const string &char_list) noexcept { - const char *pos = strpbrk(haystack.c_str(), char_list.c_str()); - if (pos == nullptr) { - return false; - } - - return string(pos, static_cast(haystack.size() - (pos - haystack.c_str()))); -} - Optional f$strpos(const string &haystack, const string &needle, int64_t offset) noexcept { if (offset < 0) { php_warning("Wrong offset = %" PRIi64 " in function strpos", offset); @@ -1899,17 +1805,6 @@ Optional f$strripos(const string &haystack, const string &needle, int64 return s - haystack.c_str(); } -string f$strrev(const string &str) noexcept { - int n = str.size(); - - string res(n, false); - for (int i = 0; i < n; i++) { - res[n - i - 1] = str[i]; - } - - return res; -} - Optional f$strstr(const string &haystack, const string &needle, bool before_needle) noexcept { if (static_cast(needle.size()) == 0) { php_warning("Parameter needle is empty in function strstr"); @@ -2290,34 +2185,6 @@ array f$str_split(const string &str, int64_t split_length) noexcept { return result; } -Optional f$substr(const string &str, int64_t start, int64_t length) noexcept { - if (!wrap_substr_args(str.size(), start, length)) { - return false; - } - return str.substr(static_cast(start), static_cast(length)); -} - -Optional f$substr(tmp_string str, int64_t start, int64_t length) noexcept { - if (!wrap_substr_args(str.size, start, length)) { - return false; - } - return string(str.data + start, length); -} - -tmp_string f$_tmp_substr(const string &str, int64_t start, int64_t length) noexcept { - if (!wrap_substr_args(str.size(), start, length)) { - return {}; - } - return {str.c_str() + start, static_cast(length)}; -} - -tmp_string f$_tmp_substr(tmp_string str, int64_t start, int64_t length) noexcept { - if (!wrap_substr_args(str.size, start, length)) { - return {}; - } - return {str.data + start, static_cast(length)}; -} - int64_t f$substr_count(const string &haystack, const string &needle, int64_t offset, int64_t length) noexcept { offset = haystack.get_correct_offset(offset); if (offset >= haystack.size()) { @@ -2397,14 +2264,6 @@ Optional f$substr_compare(const string &main_str, const string &str, in } } -bool f$str_starts_with(const string &haystack, const string &needle) noexcept { - return haystack.starts_with(needle); -} - -bool f$str_ends_with(const string &haystack, const string &needle) noexcept { - return haystack.ends_with(needle); -} - tmp_string trim_impl(const char *s, string::size_type s_len, const string &what) { const char *mask = get_mask(what); @@ -2448,19 +2307,6 @@ string f$trim(const string &s, const string &what) noexcept { return materialize_tmp_string(result); } -string f$ucfirst(const string &str) noexcept { - int n = str.size(); - if (n == 0) { - return str; - } - - string res(n, false); - res[0] = static_cast(toupper(str[0])); - memcpy(&res[1], &str[1], n - 1); - - return res; -} - string f$ucwords(const string &str) noexcept { int n = str.size(); @@ -2756,10 +2602,6 @@ Optional> f$unpack(const string &pattern, const string &data) noexc return result; } -string f$vsprintf(const string &format, const array &args) noexcept { - return f$sprintf(format, args); -} - string f$wordwrap(const string &str, int64_t width, const string &brk, bool cut) noexcept { if (width <= 0) { php_warning("Wrong parameter width = %" PRIi64 " in function wordwrap", width); diff --git a/runtime-common/stdlib/string/string-functions.h b/runtime-common/stdlib/string/string-functions.h index 4fcf15188..6cb9bd3c3 100644 --- a/runtime-common/stdlib/string/string-functions.h +++ b/runtime-common/stdlib/string/string-functions.h @@ -4,24 +4,43 @@ #pragma once +#include +#include +#include + #include "runtime-common/core/runtime-core.h" +#include "runtime-common/core/utils/kphp-assert-core.h" #include "runtime-common/stdlib/string/string-context.h" string f$addcslashes(const string &str, const string &what) noexcept; string f$addslashes(const string &str) noexcept; -string f$bin2hex(const string &str) noexcept; +string f$hex2bin(const string &str) noexcept; -string f$chop(const string &s, const string &what = StringLibConstants::get().WHAT_STR) noexcept; +inline string f$bin2hex(const string &str) noexcept { + int len = str.size(); + string result(2 * len, false); -string f$chr(int64_t v) noexcept; + for (int i = 0; i < len; i++) { + result[2 * i] = StringLibConstants::get().lhex_digits[(str[i] >> 4) & 15]; + result[2 * i + 1] = StringLibConstants::get().lhex_digits[str[i] & 15]; + } + + return result; +} string f$convert_cyr_string(const string &str, const string &from_s, const string &to_s) noexcept; -mixed f$count_chars(const string &str, int64_t mode = 0) noexcept; +inline string f$chr(int64_t v) noexcept { + return {1, static_cast(v)}; +} -string f$hex2bin(const string &str) noexcept; +inline int64_t f$ord(const string &s) noexcept { + return static_cast(s[0]); +} + +mixed f$count_chars(const string &str, int64_t mode = 0) noexcept; string f$htmlentities(const string &str) noexcept; @@ -32,7 +51,18 @@ string f$htmlspecialchars(const string &str, int64_t flags = StringLibConstants: string f$htmlspecialchars_decode(const string &str, int64_t flags = StringLibConstants::ENT_COMPAT | StringLibConstants::ENT_HTML401) noexcept; -string f$lcfirst(const string &str) noexcept; +inline string f$lcfirst(const string &str) noexcept { + int n = str.size(); + if (n == 0) { + return str; + } + + string res(n, false); + res[0] = static_cast(tolower(str[0])); + memcpy(&res[1], &str[1], n - 1); + + return res; +} int64_t f$levenshtein(const string &str1, const string &str2) noexcept; @@ -44,15 +74,15 @@ string f$nl2br(const string &str, bool is_xhtml = true) noexcept; string f$number_format(double number, int64_t decimals, const string &dec_point, const string &thousands_sep) noexcept; -int64_t f$ord(const string &s) noexcept; - string f$pack(const string &pattern, const array &a) noexcept; string f$prepare_search_query(const string &query) noexcept; string f$rtrim(const string &s, const string &what = StringLibConstants::get().WHAT_STR) noexcept; -Optional f$setlocale(int64_t category, const string &locale) noexcept; +inline string f$chop(const string &s, const string &what = StringLibConstants::get().WHAT_STR) noexcept { + return f$rtrim(s, what); +} string f$sprintf(const string &format, const array &a) noexcept; @@ -60,35 +90,72 @@ string f$stripcslashes(const string &str) noexcept; string f$stripslashes(const string &str) noexcept; -int64_t f$strcasecmp(const string &lhs, const string &rhs) noexcept; +inline int64_t f$strcasecmp(const string &lhs, const string &rhs) noexcept { + int n = min(lhs.size(), rhs.size()); + for (int i = 0; i < n; i++) { + if (tolower(lhs[i]) != tolower(rhs[i])) { + return tolower(lhs[i]) - tolower(rhs[i]); + } + } + // TODO: for PHP8.2, use <=> operator instead: + // return spaceship(static_cast(lhs.size()), static_cast(rhs.size())); + return static_cast(lhs.size()) - static_cast(rhs.size()); +} -int64_t f$strcmp(const string &lhs, const string &rhs) noexcept; +inline int64_t f$strcmp(const string &lhs, const string &rhs) noexcept { + return lhs.compare(rhs); +} -string f$strip_tags(const string &str, const array &allow) noexcept; +string f$strip_tags(const string &str, const string &allow = string{}); + +inline string f$strip_tags(const string &str, const array &allow_list) noexcept { + php_assert(allow_list.empty()); + return f$strip_tags(str, string()); +} string f$strip_tags(const string &str, const mixed &allow); string f$strip_tags(const string &str, const array &allow_list); -string f$strip_tags(const string &str, const string &allow = string{}); - Optional f$stripos(const string &haystack, const string &needle, int64_t offset = 0) noexcept; -inline Optional f$stripos(const string &haystack, const mixed &needle, int64_t offset = 0) noexcept; +inline Optional f$stripos(const string &haystack, const mixed &needle, int64_t offset = 0) noexcept { + if (needle.is_string()) { + return f$stripos(haystack, needle.to_string(), offset); + } else { + return f$stripos(haystack, string(1, static_cast(needle.to_int())), offset); + } +} Optional f$stristr(const string &haystack, const string &needle, bool before_needle = false) noexcept; Optional f$strrchr(const string &haystack, const string &needle) noexcept; -int64_t f$strncmp(const string &lhs, const string &rhs, int64_t len) noexcept; +inline int64_t f$strncmp(const string &lhs, const string &rhs, int64_t len) noexcept { + if (len < 0) { + return 0; + } + return std::memcmp(lhs.c_str(), rhs.c_str(), min(int64_t{min(lhs.size(), rhs.size())} + 1, len)); +} int64_t f$strnatcmp(const string &lhs, const string &rhs) noexcept; -int64_t f$strspn(const string &hayshack, const string &char_list, int64_t offset = 0) noexcept; +inline int64_t f$strspn(const string &hayshack, const string &char_list, int64_t offset = 0) noexcept { + return std::strspn(hayshack.c_str() + hayshack.get_correct_offset_clamped(offset), char_list.c_str()); +} -int64_t f$strcspn(const string &hayshack, const string &char_list, int64_t offset = 0) noexcept; +inline int64_t f$strcspn(const string &hayshack, const string &char_list, int64_t offset = 0) noexcept { + return std::strcspn(hayshack.c_str() + hayshack.get_correct_offset_clamped(offset), char_list.c_str()); +} -Optional f$strpbrk(const string &haystack, const string &char_list) noexcept; +inline Optional f$strpbrk(const string &haystack, const string &char_list) noexcept { + const char *pos = std::strpbrk(haystack.c_str(), char_list.c_str()); + if (pos == nullptr) { + return false; + } + + return string(pos, static_cast(haystack.size() - (pos - haystack.c_str()))); +} Optional f$strpos(const string &haystack, const string &needle, int64_t offset = 0) noexcept; @@ -109,7 +176,16 @@ Optional f$strrpos(const string &haystack, const string &needle, int64_ Optional f$strripos(const string &haystack, const string &needle, int64_t offset = 0) noexcept; -string f$strrev(const string &str) noexcept; +inline string f$strrev(const string &str) noexcept { + int n = str.size(); + + string res(n, false); + for (int i = 0; i < n; i++) { + res[n - i - 1] = str[i]; + } + + return res; +} Optional f$strstr(const string &haystack, const string &needle, bool before_needle = false) noexcept; @@ -119,10 +195,6 @@ string f$strtoupper(const string &str) noexcept; string f$strtr(const string &subject, const string &from, const string &to) noexcept; -// inline string f$strtr(const string &subject, const mixed &from, const mixed &to); - -// inline string f$strtr(const string &subject, const mixed &replace_pairs); - string f$str_pad(const string &input, int64_t len, const string &pad_str = StringLibConstants::get().SPACE_STR, int64_t pad_type = StringLibConstants::STR_PAD_RIGHT) noexcept; @@ -203,13 +275,33 @@ mixed f$str_ireplace(const mixed &search, const mixed &replace, const mixed &sub array f$str_split(const string &str, int64_t split_length = 1) noexcept; -Optional f$substr(const string &str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept; +inline Optional f$substr(const string &str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept { + if (!wrap_substr_args(str.size(), start, length)) { + return false; + } + return str.substr(static_cast(start), static_cast(length)); +} -Optional f$substr(tmp_string, int64_t start, int64_t length = std::numeric_limits::max()) noexcept; +inline Optional f$substr(tmp_string str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept { + if (!wrap_substr_args(str.size, start, length)) { + return false; + } + return string(str.data + start, length); +} -tmp_string f$_tmp_substr(const string &str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept; +inline tmp_string f$_tmp_substr(const string &str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept { + if (!wrap_substr_args(str.size(), start, length)) { + return {}; + } + return {str.c_str() + start, static_cast(length)}; +} -tmp_string f$_tmp_substr(tmp_string str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept; +inline tmp_string f$_tmp_substr(tmp_string str, int64_t start, int64_t length = std::numeric_limits::max()) noexcept { + if (!wrap_substr_args(str.size, start, length)) { + return {}; + } + return {str.data + start, static_cast(length)}; +} int64_t f$substr_count(const string &haystack, const string &needle, int64_t offset = 0, int64_t length = std::numeric_limits::max()) noexcept; @@ -218,9 +310,13 @@ string f$substr_replace(const string &str, const string &replacement, int64_t st Optional f$substr_compare(const string &main_str, const string &str, int64_t offset, int64_t length = std::numeric_limits::max(), bool case_insensitivity = false) noexcept; -bool f$str_starts_with(const string &haystack, const string &needle) noexcept; +inline bool f$str_starts_with(const string &haystack, const string &needle) noexcept { + return haystack.starts_with(needle); +} -bool f$str_ends_with(const string &haystack, const string &needle) noexcept; +inline bool f$str_ends_with(const string &haystack, const string &needle) noexcept { + return haystack.ends_with(needle); +} tmp_string f$_tmp_trim(tmp_string s, const string &what = StringLibConstants::get().WHAT_STR) noexcept; @@ -230,23 +326,30 @@ string f$trim(tmp_string s, const string &what = StringLibConstants::get().WHAT_ string f$trim(const string &s, const string &what = StringLibConstants::get().WHAT_STR) noexcept; -string f$ucfirst(const string &str) noexcept; +inline string f$ucfirst(const string &str) noexcept { + int n = str.size(); + if (n == 0) { + return str; + } + + string res(n, false); + res[0] = static_cast(toupper(str[0])); + memcpy(&res[1], &str[1], n - 1); + + return res; +} string f$ucwords(const string &str) noexcept; Optional> f$unpack(const string &pattern, const string &data) noexcept; -string f$vsprintf(const string &format, const array &args) noexcept; +inline string f$vsprintf(const string &format, const array &args) noexcept { + return f$sprintf(format, args); +} string f$wordwrap(const string &str, int64_t width = 75, const string &brk = StringLibConstants::get().NEWLINE_STR, bool cut = false) noexcept; -/* - * - * IMPLEMENTATION - * - */ - -namespace impl_ { +namespace hex2char_impl_ { struct Hex2CharMapMaker { private: @@ -266,10 +369,10 @@ struct Hex2CharMapMaker { } }; -} // namespace impl_ +}; // namespace hex2char_impl_ inline uint8_t hex_to_int(char c) noexcept { - static constexpr auto hex_int_map = impl_::Hex2CharMapMaker::make(std::make_index_sequence<256>()); + static constexpr auto hex_int_map = hex2char_impl_::Hex2CharMapMaker::make(std::make_index_sequence<256>()); return hex_int_map[static_cast(c)]; } @@ -303,14 +406,6 @@ inline int64_t f$strlen(const string &s) noexcept { return s.size(); } -inline Optional f$stripos(const string &haystack, const mixed &needle, int64_t offset) noexcept { - if (needle.is_string()) { - return f$stripos(haystack, needle.to_string(), offset); - } else { - return f$stripos(haystack, string(1, static_cast(needle.to_int())), offset); - } -} - inline Optional f$stristr(const string &haystack, const mixed &needle, bool before_needle = false) noexcept { if (needle.is_string()) { return f$stristr(haystack, needle.to_string(), before_needle); diff --git a/runtime/string_functions.cpp b/runtime/string_functions.cpp index 610129816..2acb714ec 100644 --- a/runtime/string_functions.cpp +++ b/runtime/string_functions.cpp @@ -17,6 +17,18 @@ int64_t f$vprintf(const string &format, const array &args) noexcept { return f$printf(format, args); } +Optional f$setlocale(int64_t category, const string &locale) noexcept { + const char *loc = locale.c_str(); + if (locale[0] == '0' && locale.size() == 1) { + loc = nullptr; + } + char *res = setlocale(static_cast(category), loc); + if (res == nullptr) { + return false; + } + return string(res); +} + // Based on `getcsv` from `streams` Optional> f$str_getcsv(const string &str, const string &delimiter, const string &enclosure, const string &escape) noexcept { char delimiter_char = ','; diff --git a/runtime/string_functions.h b/runtime/string_functions.h index eb3baf2d5..ad5c328d5 100644 --- a/runtime/string_functions.h +++ b/runtime/string_functions.h @@ -13,6 +13,8 @@ int64_t f$printf(const string &format, const array &a) noexcept; int64_t f$vprintf(const string &format, const array &args) noexcept; +Optional f$setlocale(int64_t category, const string &locale) noexcept; + Optional> f$str_getcsv(const string &s, const string &delimiter = StringLibConstants::get().COMMA_STR, const string &enclosure = StringLibConstants::get().QUOTE_STR, const string &escape = StringLibConstants::get().BACKSLASH_STR) noexcept;