From c6eec109f8e5f39c042de61270c641b4e06652fa Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 30 Oct 2026 13:31:44 +0100 Subject: [PATCH] [native] Remove unused C++ helpers Remove the unreferenced custom string implementation and HostUtil helper, along with unused mapping, DSO loading, filesystem, search, JNI wrapper, and C++ utility helpers. Remove obsolete build and include references. Keep the active RuntimeUtil, path-based DSO loading, and stateless lower_bound implementations unchanged. Include directly for the remaining std::invoke usage instead of relying on . Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/native/clr/host/CMakeLists.txt | 1 - src/native/clr/host/host-util.cc | 19 - src/native/clr/host/host.cc | 1 - src/native/clr/include/host/host-util.hh | 11 - src/native/clr/include/runtime-base/util.hh | 84 -- src/native/clr/runtime-base/util.cc | 42 - .../common/include/runtime-base/dso-loader.hh | 19 - .../include/runtime-base/jni-wrappers.hh | 5 - .../common/include/runtime-base/search.hh | 42 - .../common/include/runtime-base/strings.hh | 989 ------------------ src/native/common/include/shared/cpp-util.hh | 66 +- 11 files changed, 1 insertion(+), 1278 deletions(-) delete mode 100644 src/native/clr/host/host-util.cc delete mode 100644 src/native/clr/include/host/host-util.hh delete mode 100644 src/native/common/include/runtime-base/strings.hh diff --git a/src/native/clr/host/CMakeLists.txt b/src/native/clr/host/CMakeLists.txt index 5e91dfdbaa0..e23a6546d4c 100644 --- a/src/native/clr/host/CMakeLists.txt +++ b/src/native/clr/host/CMakeLists.txt @@ -28,7 +28,6 @@ set(XAMARIN_MONODROID_SOURCES coreclr-bootstrap.cc host-jni.cc host-shared.cc - host-util.cc gc-bridge.cc os-bridge.cc runtime-environment.cc diff --git a/src/native/clr/host/host-util.cc b/src/native/clr/host/host-util.cc deleted file mode 100644 index 1a1e49d8e34..00000000000 --- a/src/native/clr/host/host-util.cc +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -using namespace xamarin::android; - -auto HostUtil::get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) noexcept -> jclass -{ - static constexpr char java_lang_class_sig[] = "Ljava/lang/Class;"; - - jfieldID fieldID = env->GetStaticFieldID (runtime, name, java_lang_class_sig); - if (fieldID == nullptr) - return nullptr; - - jobject field = env->GetStaticObjectField (runtime, fieldID); - if (field == nullptr) - return nullptr; - - return reinterpret_cast (make_gref ? OSBridge::lref_to_gref (env, field) : field); -} diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 81223b3edea..ee665c868d6 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/src/native/clr/include/host/host-util.hh b/src/native/clr/include/host/host-util.hh deleted file mode 100644 index 8fb9edc0873..00000000000 --- a/src/native/clr/include/host/host-util.hh +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include - -namespace xamarin::android { - class HostUtil - { - public: - static auto get_class_from_runtime_field (JNIEnv *env, jclass runtime, const char *name, bool make_gref) noexcept -> jclass; - }; -} diff --git a/src/native/clr/include/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 9cd2c8eb02f..97471abf6d5 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -1,8 +1,6 @@ #pragma once -#include #include -#include #include #include @@ -20,21 +18,8 @@ #include namespace xamarin::android { - namespace detail { - struct mmap_info - { - void *area; - size_t size; - }; - } - class Util { - static constexpr inline char hex_map [16] { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', - }; - public: static constexpr size_t LocalPathBufferSize = Constants::SENSIBLE_PATH_MAX; @@ -61,22 +46,6 @@ namespace xamarin::android { } static void create_public_directory (const char *dir); - static auto monodroid_fopen (const char *filename, const char *mode) noexcept -> FILE*; - static void set_world_accessable (const char *path); - static auto set_world_accessible (int fd) noexcept -> bool; - - // Puts higher half of the `value` byte as a hexadecimal character in `high_half` and - // the lower half in `low_half` - static void to_hex (uint8_t value, char &high_half, char &low_half) noexcept - { - high_half = hex_map[(value & 0xf0) >> 4]; - low_half = hex_map[value & 0x0f]; - } - - static auto should_log (LogCategories category) noexcept -> bool - { - return (log_categories & category) != 0; - } private: static auto fs_entry_is_mode (struct stat const& s, mode_t mode) noexcept -> bool @@ -215,56 +184,6 @@ namespace xamarin::android { set_environment_variable_for_directory (name, value, true, Constants::DEFAULT_DIRECTORY_MODE); } - static int monodroid_getpagesize () noexcept - { - return page_size; - } - - static detail::mmap_info mmap_file (int fd, uint32_t offset, size_t size, std::string_view const& filename) noexcept - { - detail::mmap_info file_info; - detail::mmap_info mmap_info; - - size_t pageSize = static_cast(Util::monodroid_getpagesize ()); - size_t offsetFromPage = offset % pageSize; - size_t offsetPage = offset - offsetFromPage; - size_t offsetSize = size + offsetFromPage; - - mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); - - if (mmap_info.area == MAP_FAILED) { - Helpers::abort_applicationf ( - LOG_ASSEMBLY, - std::source_location::current (), - "Could not mmap APK fd %d: %s; File=%.*s", - fd, - strerror (errno), - static_cast(filename.length ()), - filename.data () - ); - } - - mmap_info.size = offsetSize; - file_info.area = pointer_add (mmap_info.area, offsetFromPage); - file_info.size = size; - - log_infof ( - LOG_ASSEMBLY, - " mmap_start: %-8p; mmap_end: %-8p\t mmap_len: %-12zu file_start: %-8p file_end: %-8p\t file_len: %-12zu\t apk descriptor: %d file: %.*s", - mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), - mmap_info.size, - file_info.area, - pointer_add (file_info.area, file_info.size), - file_info.size, - fd, - static_cast(filename.length ()), - filename.data () - ); - - return file_info; - } - static auto is_path_rooted (const char *path) noexcept -> bool { if (path == nullptr) { @@ -434,8 +353,5 @@ namespace xamarin::android { abort_unless (result >= 0, "Failed to format DSO name using the required capacity"); return heap_buffer; } - - private: - static inline int page_size = getpagesize (); }; } diff --git a/src/native/clr/runtime-base/util.cc b/src/native/clr/runtime-base/util.cc index 641b1aa1636..d8850f4c9f1 100644 --- a/src/native/clr/runtime-base/util.cc +++ b/src/native/clr/runtime-base/util.cc @@ -76,45 +76,3 @@ Util::create_public_directory (const char *dir) } umask (m); } - -auto -Util::monodroid_fopen (const char *filename, const char *mode) noexcept -> FILE* -{ - /* On Unix, both path and system calls are all assumed - * to be UTF-8 compliant. - */ - FILE *ret = fopen (filename, mode); - if (ret == nullptr) { - log_errorf (LOG_DEFAULT, "fopen failed for file %s: %s", filename, strerror (errno)); - return nullptr; - } - - return ret; -} - -void Util::set_world_accessable (const char *path) -{ - int r; - do { - r = chmod (path, 0664); - } while (r == -1 && errno == EINTR); - - if (r == -1) { - log_errorf (LOG_DEFAULT, "chmod(\"%s\", 0664) failed: %s", path, strerror (errno)); - } -} - -auto Util::set_world_accessible (int fd) noexcept -> bool -{ - int r; - do { - r = fchmod (fd, 0664); - } while (r == -1 && errno == EINTR); - - if (r == -1) { - log_errorf (LOG_DEFAULT, "fchmod() failed: %s", strerror (errno)); - return false; - } - - return true; -} diff --git a/src/native/common/include/runtime-base/dso-loader.hh b/src/native/common/include/runtime-base/dso-loader.hh index f4615511322..e642c2fca3f 100644 --- a/src/native/common/include/runtime-base/dso-loader.hh +++ b/src/native/common/include/runtime-base/dso-loader.hh @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -52,24 +51,6 @@ namespace xamarin::android { return log_and_return (dlopen (path.data (), flags), path); } - // Overload used to load libraries from the APK. - [[gnu::always_inline, gnu::flatten]] - static auto load (int fd, off64_t offset, std::string_view const& name, int flags, bool is_jni) -> void* - { - if (is_jni) { - return load_jni (name, true /* name_is_path */); - } - - log_infof (LOG_ASSEMBLY, "[apk] Trying to load shared library '%.*s', offset in the apk == %lld", static_cast(name.length ()), name.data (), static_cast(offset)); - - android_dlextinfo dli; - dli.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; - dli.library_fd = fd; - dli.library_fd_offset = offset; - - return log_and_return (android_dlopen_ext (name.data (), flags, &dli), name); - } - private: [[gnu::always_inline]] static auto log_and_return (void *handle, std::string_view const& full_name) -> void* diff --git a/src/native/common/include/runtime-base/jni-wrappers.hh b/src/native/common/include/runtime-base/jni-wrappers.hh index c0390b64252..d5364920af0 100644 --- a/src/native/common/include/runtime-base/jni-wrappers.hh +++ b/src/native/common/include/runtime-base/jni-wrappers.hh @@ -46,11 +46,6 @@ namespace xamarin::android jstring_wrapper& operator=(const jstring_wrapper&) = delete; - bool hasValue () noexcept - { - return jstr != nullptr; - } - private: [[gnu::always_inline]] void ensure_cstr () noexcept diff --git a/src/native/common/include/runtime-base/search.hh b/src/native/common/include/runtime-base/search.hh index 0bb132eda49..746d0a5edd2 100644 --- a/src/native/common/include/runtime-base/search.hh +++ b/src/native/common/include/runtime-base/search.hh @@ -2,33 +2,11 @@ #pragma once #include -#include namespace xamarin::android { class Search final { public: - template - [[gnu::always_inline, gnu::flatten]] - static size_t lower_bound (const TState& state, TKey key, const T *arr, size_t n) noexcept - { - static_assert (less_than != nullptr, "less_than is a required template parameter"); - - size_t left = 0; - size_t right = n; - - while (left < right) { - size_t middle = (left + right) >> 1u; - if (less_than (arr[middle], key, state)) { - left = middle + 1; - } else { - right = middle; - } - } - - return left; - } - template [[gnu::always_inline, gnu::flatten]] static size_t lower_bound (TKey key, const T *arr, size_t n) noexcept @@ -49,25 +27,5 @@ namespace xamarin::android { return left; } - - template - [[gnu::always_inline, gnu::flatten]] - static ssize_t binary_search (const TState& state, TKey key, const T *arr, size_t n) noexcept - { - static_assert (equal != nullptr, "equal is a required template parameter"); - - size_t idx = lower_bound (state, key, arr, n); - return idx < n && equal (arr[idx], key, state) ? static_cast(idx) : -1z; - } - - template - [[gnu::always_inline, gnu::flatten]] - static ssize_t binary_search (TKey key, const T *arr, size_t n) noexcept - { - static_assert (equal != nullptr, "equal is a required template parameter"); - - size_t idx = lower_bound (key, arr, n); - return idx < n && equal (arr[idx], key) ? static_cast(idx) : -1z; - } }; } diff --git a/src/native/common/include/runtime-base/strings.hh b/src/native/common/include/runtime-base/strings.hh deleted file mode 100644 index 157ba36b050..00000000000 --- a/src/native/common/include/runtime-base/strings.hh +++ /dev/null @@ -1,989 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(XA_HOST_MONOVM) -#include - -using Constants = xamarin::android::internal::SharedConstants; -#else -#include -#endif - -namespace xamarin::android { - static constexpr size_t SENSIBLE_TYPE_NAME_LENGTH = 128uz; - static constexpr size_t SENSIBLE_PATH_MAX = 256uz; - -#if DEBUG - static constexpr bool BoundsCheck = true; -#else - static constexpr bool BoundsCheck = false; -#endif - - enum class string_segment_error - { - index_out_of_range, - }; - - static constexpr auto to_string (string_segment_error error) -> const char* - { - switch (error) { - case string_segment_error::index_out_of_range: - return "Index out of range"; - - default: - return "Unknown error"; - } - } - - class string_segment - { - public: - [[gnu::always_inline]] - auto initialized () const noexcept -> bool - { - return !_fresh; - } - - [[gnu::always_inline]] - auto start () const noexcept -> const char* - { - return _start; - } - - [[gnu::always_inline]] - auto at (size_t offset) const noexcept -> std::expected - { - if (offset >= length ()) { - return std::unexpected (string_segment_error::index_out_of_range); - } - - return _start + offset; - } - - [[gnu::always_inline]] - auto length () const noexcept -> size_t - { - return _length; - } - - [[gnu::always_inline]] - auto empty () const noexcept -> bool - { - return length () == 0; - } - - [[gnu::always_inline]] - auto equal (const char *s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return equal (s, strlen (s)); - } - - [[gnu::always_inline]] - auto equal (const char *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - if (length () != s_length) { - return false; - } - - if (!can_access (s_length)) [[unlikely]] { - return false; - } - - if (length () == 0) { - return true; - } - - return memcmp (_start, s, length ()) == 0; - } - - template [[gnu::always_inline]] - auto equal (const char (&s)[Size]) noexcept -> bool - { - return equal (s, Size - 1); - } - - [[gnu::always_inline]] - auto equal (std::string_view const& s) noexcept -> bool - { - return equal (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto starts_with_c (const char *s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return starts_with (s, strlen (s)); - } - - [[gnu::always_inline]] - auto starts_with (const char *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr || !can_access (s_length)) { - return false; - } - - if (length () < s_length) { - return false; - } - - return memcmp (start (), s, s_length) == 0; - } - - template [[gnu::always_inline]] - auto starts_with (const char (&s)[Size]) const noexcept -> bool - { - return starts_with (s, Size - 1); - } - - [[gnu::always_inline]] - auto starts_with (std::string_view const& s) const noexcept -> bool - { - return starts_with (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto has_at (const char ch, size_t index) const noexcept -> bool - { - if (!can_access (index)) { - return false; - } - - return start ()[index] == ch; - } - - [[gnu::always_inline]] - auto find (const char ch, size_t start_index) const noexcept -> ssize_t - { - if (!can_access (start_index)) { - return -1; - } - - while (start_index <= length ()) { - if (start ()[start_index] == ch) { - return static_cast(start_index); - } - start_index++; - } - - return -1; - } - - template [[gnu::always_inline]] - auto to_integer (T &val, size_t start_index = 0uz, int base = 10) const noexcept -> bool - { - static_assert (std::is_integral_v); - constexpr T min = std::numeric_limits::min (); - constexpr T max = std::numeric_limits::max (); - using integer = typename std::conditional, int64_t, uint64_t>::type; - - if (length () == 0uz) { - return false; - } - - if (!can_access (start_index)) { - log_errorf (LOG_DEFAULT, "Cannot convert string to integer, index %zu is out of range", start_index); - return false; - } - - // FIXME: this is less than ideal... we shouldn't need another buffer here - size_t slen = length () - start_index; - char s[slen + 1]; - - memcpy (s, start () + start_index, slen); - s[slen] = '\0'; - - integer ret; - char *endp; - bool out_of_range; - errno = 0; - if constexpr (std::is_signed_v) { - ret = strtoll (s, &endp, base); - out_of_range = ret < min || ret > max; - } else { - ret = strtoull (s, &endp, base); - out_of_range = ret > max; - } - - if (out_of_range || errno == ERANGE) { - log_errorf ( - LOG_DEFAULT, - "Value %s is out of range of this type (%lld..%llu)", - reinterpret_cast(s), - static_cast(static_cast(min)), - static_cast(static_cast(max)) - ); - return false; - } - - if (endp == s) { - log_errorf (LOG_DEFAULT, "Value %s does not represent a base %d integer", reinterpret_cast(s), base); - return false; - } - - if (*endp != '\0') { - log_errorf (LOG_DEFAULT, "Value %s has non-numeric characters at the end", reinterpret_cast(s)); - return false; - } - - val = static_cast(ret); - return true; - } - - private: - [[gnu::always_inline]] - auto can_access (size_t index) const noexcept -> bool - { - if (!initialized () || start () == nullptr) [[unlikely]] { - return false; - } - - if (index > length ()) { - return false; - } - - return true; - } - - protected: - size_t _last_index = 0uz; - bool _fresh = true; - const char *_start = nullptr; - size_t _length = 0uz; - - template friend class string_base; - }; - - template - class local_storage - { - protected: - using LocalStoreArray = std::array; - - public: - static constexpr bool has_resize = HasResize; - - public: - explicit local_storage (size_t size) noexcept - { - static_assert (MaxStackSize > 0, "MaxStackSize must be more than 0"); - init_store (size < MaxStackSize ? MaxStackSize : size); - } - - virtual ~local_storage () - { - free_store (); - } - - auto get () noexcept -> T* - { - return allocated_store == nullptr ? local_store.data () : allocated_store; - } - - auto get () const noexcept -> const T* - { - return allocated_store == nullptr ? local_store.data () : allocated_store; - } - - auto size () const noexcept -> size_t - { - return store_size; - } - - protected: - [[gnu::always_inline]] - void init_store (size_t new_size) noexcept - { - if (new_size > MaxStackSize) { - allocated_store = new T[new_size]; - } else { - allocated_store = nullptr; - } - store_size = new_size; - } - - [[gnu::always_inline]] - void free_store () noexcept - { - if (allocated_store == nullptr) { - return; - } - - delete[] allocated_store; - } - - [[gnu::always_inline]] - auto get_local_store () noexcept -> LocalStoreArray& - { - return local_store; - } - - [[gnu::always_inline]] - auto get_allocated_store () noexcept -> T* - { - return allocated_store; - } - - private: - size_t store_size; - LocalStoreArray local_store; - T* allocated_store; - }; - - // This class is meant to provide a *very* thin veneer (by design) over space allocated for *local* buffers - that - // is one which are not meant to survive the exit of the function they are created in. The idea is that the caller - // knows the size of the buffer they need and they want to put the buffer on stack, if it doesn't exceed a certain - // value, or dynamically allocate memory if more is needed. Even though the class could be used on its own, it's - // really meant to be a base for more specialized buffers. There are not many safeguards, by design - the code is - // meant to be performant. This is the reason why the size is static throughout the life of the object, so that we - // can perform as few checks as possible. - - template using static_local_storage_base = local_storage; - - template - class static_local_storage final : public static_local_storage_base - { - using base = static_local_storage_base; - - public: - explicit static_local_storage (size_t initial_size) noexcept - : base (initial_size) - {} - }; - - template using dynamic_local_storage_base = local_storage; - - template - class dynamic_local_storage final : public dynamic_local_storage_base - { - using base = dynamic_local_storage_base; - - public: - explicit dynamic_local_storage (size_t initial_size = 0uz) noexcept - : base (initial_size) - {} - - // - // If `new_size` is smaller than the current size and the dynamic store is allocated, data WILL NOT be - // preserved. - // - // If `new_size` is bigger than the current size bigger than MaxStackSize, data will be copied to the new - // dynamically allocated store - // - // If `new_size` is smaller or equal to `MaxStackSize`, no changes are made unless dynamic store was allocated, - // in which case it will be freed - // - void resize (size_t new_size) noexcept - { - size_t old_size = base::size (); - - if (new_size == old_size) { - return; - } - - if (new_size <= MaxStackSize) { - new_size = MaxStackSize; - base::free_store (); - return; - } - - if (new_size < old_size) { - base::free_store (); - base::init_store (new_size); - return; - } - - T* old_allocated_store = base::get_allocated_store (); - base::init_store (new_size); - - T* new_allocated_store = base::get_allocated_store (); - if (old_allocated_store != nullptr) { - std::memcpy (new_allocated_store, old_allocated_store, old_size); - delete[] old_allocated_store; - return; - } - - std::memcpy (new_allocated_store, base::get_local_store ().data (), MaxStackSize); - } - }; - - template - class string_base - { - protected: - static constexpr TChar NUL = '\0'; - static constexpr TChar ZERO = '0'; - - public: - explicit string_base (size_t initial_size = 0uz) - : buffer (initial_size) - { - // Currently we care only about `char`, maybe in the future we'll add support for `wchar` (if needed) - static_assert (std::is_same_v, "TChar must be an 8-bit character type"); - - clear (); - } - - explicit string_base (const string_segment &token) - : string_base (token.initialized () ? token.length () : 0) - { - if (token.initialized ()) { - assign (token.start (), token.length ()); - } - } - - [[gnu::always_inline]] - auto length () const noexcept -> size_t - { - return idx; - } - - [[gnu::always_inline]] - auto empty () const noexcept -> bool - { - return length () == 0; - } - - [[gnu::always_inline]] - void set_length (size_t new_length) noexcept - { - if (new_length >= buffer.size ()) { - return; - } - - idx = new_length; - terminate (); - } - - [[gnu::always_inline]] - void clear () noexcept - { - set_length (0); - buffer.get ()[0] = NUL; - } - - [[gnu::always_inline]] - void terminate () noexcept - { - buffer.get ()[idx] = NUL; - } - - [[gnu::always_inline]] - auto replace (const TChar c1, const TChar c2) noexcept -> string_base& - { - if (empty ()) { - return *this; - } - - for (size_t i = 0uz; i < length (); i++) { - if (buffer.get ()[i] == c1) { - buffer.get ()[i] = c2; - } - } - - return *this; - } - - [[gnu::always_inline]] - auto append (const TChar* s, size_t length) noexcept -> string_base& - { - if (s == nullptr || length == 0uz) { - return *this; - } - - resize_for_extra (length); - if constexpr (BoundsCheck) { - ensure_have_extra (length); - } - - std::memcpy (buffer.get () + idx, s, length); - idx += length; - buffer.get ()[idx] = NUL; - - return *this; - } - - template - [[gnu::always_inline]] - auto append (string_base const& str) noexcept -> string_base& - { - return append (str.get (), str.length ()); - } - - [[gnu::always_inline]] - auto append (std::string_view const& sv) noexcept -> string_base& - { - return append (sv.data (), sv.length ()); - } - - template [[gnu::always_inline]] - auto append (const char (&s)[Size]) noexcept -> string_base& - { - return append (s, Size - 1); - } - - [[gnu::always_inline]] - auto append_c (const char *s) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - return append (s, strlen (s)); - } - - [[gnu::always_inline]] - auto append (int16_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (buffer.get (), i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint16_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (int32_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint32_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (int64_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto append (uint64_t i) noexcept -> string_base& - { - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - append_integer (i); - return *this; - } - - [[gnu::always_inline]] - auto assign (const TChar* s, size_t length) noexcept -> string_base& - { - idx = 0; - return append (s, length); - } - - [[gnu::always_inline]] - auto assign_c (const TChar* s) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - return assign (s, strlen (s)); - } - - [[gnu::always_inline]] - auto assign (std::string_view const& sv) noexcept -> string_base& - { - return assign (sv.data (), sv.size ()); - } - - [[gnu::always_inline]] - auto assign (std::string const& s) noexcept -> string_base& - { - return assign (s.data (), s.size ()); - } - - template [[gnu::always_inline]] - auto assign (const char (&s)[Size]) noexcept -> string_base& - { - return assign (s, Size - 1); - } - - template - [[gnu::always_inline]] - auto assign (string_base const& str) noexcept -> string_base& - { - return assign (str.get (), str.length ()); - } - - [[gnu::always_inline]] - auto assign (const TChar* s, size_t offset, size_t count) noexcept -> string_base& - { - if (s == nullptr) { - return *this; - } - - if constexpr (BoundsCheck) { - size_t slen = strlen (s); - if (offset + count > slen) { - Helpers::abort_application ("Attempt to assign data from a string exceeds the source string length"); - } - } - - return assign (s + offset, count); - } - - [[gnu::always_inline]] - auto next_token (size_t start_index, const TChar separator, string_segment& token) const noexcept -> bool - { - size_t index; - if (token._fresh) { - token._fresh = false; - token._last_index = start_index; - index = start_index; - } else { - index = token._last_index + 1; - } - - token._start = nullptr; - token._length = 0; - if (token._last_index + 1 >= buffer.size ()) { - return false; - } - - const TChar *start = buffer.get () + index; - const TChar *p = start; - while (*p != NUL) { - if (*p == separator) { - break; - } - p++; - index++; - } - - token._last_index = *p == NUL ? buffer.size () : index; - token._start = start; - token._length = static_cast(p - start); - - return true; - } - - [[gnu::always_inline]] - auto next_token (const char separator, string_segment& token) const noexcept -> bool - { - return next_token (0, separator, token); - } - - [[gnu::always_inline]] - auto index_of (const TChar ch) const noexcept -> ssize_t - { - const TChar *p = buffer.get (); - while (p != nullptr && *p != NUL) { - if (*p == ch) { - return static_cast(p - buffer.get ()); - } - p++; - } - - return -1; - } - - [[gnu::always_inline]] - auto starts_with (const TChar *s, size_t s_length) const noexcept -> bool - { - if (s == nullptr || s_length == 0 || s_length > buffer.size ()) { - return false; - } - - return memcmp (buffer.get (), s, s_length) == 0; - } - - [[gnu::always_inline]] - auto starts_with_c (const char* s) const noexcept -> bool - { - if (s == nullptr) { - return false; - } - - return starts_with (s, strlen (s)); - } - - template [[gnu::always_inline]] - auto starts_with (const char (&s)[Size]) const noexcept -> bool - { - return starts_with (s, Size - 1); - } - - [[gnu::always_inline]] - auto starts_with (std::string_view const& s) const noexcept -> bool - { - return starts_with (s.data (), s.length ()); - } - - [[gnu::always_inline]] - auto ends_with (std::string_view const& s) const noexcept -> bool - { - if (empty () || s.length () > buffer.size ()) { - return false; - } - - return memcmp (buffer.get () + (length () - s.length ()), s.data (), s.length ()) == 0; - } - - [[gnu::always_inline]] - void set_length_after_direct_write (size_t new_length) noexcept - { - set_length (new_length); - terminate (); - } - - [[gnu::always_inline]] - void set_at (size_t index, const TChar ch) noexcept - { - ensure_valid_index (index); - TChar *p = buffer + index; - if (*p == NUL) { - return; - } - - *p = ch; - } - - [[gnu::always_inline]] - auto get_at (size_t index) const noexcept -> const TChar - { - ensure_valid_index (index); - return *(buffer.get () + index); - } - - [[gnu::always_inline]] - auto get_at (size_t index) noexcept -> TChar& - { - ensure_valid_index (index); - return *(buffer.get () + index); - } - - [[gnu::always_inline]] - auto get () const noexcept -> const TChar* - { - return buffer.get (); - } - - [[gnu::always_inline]] - auto get () noexcept -> TChar* - { - return buffer.get (); - } - - [[gnu::always_inline]] - auto size () const noexcept -> size_t - { - return buffer.size (); - } - - [[gnu::always_inline]] - auto operator[] (size_t index) const noexcept -> char - { - return get_at (index); - } - - [[gnu::always_inline]] - auto operator[] (size_t index) noexcept -> char& - { - return get_at (index); - } - - [[gnu::always_inline]] - auto as_string_view () const noexcept -> std::string_view - { - return { get (), length () }; - } - - protected: - template [[gnu::always_inline]] - void append_integer (Integer i) noexcept - { - static_assert (std::is_integral_v); - - resize_for_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - if constexpr (BoundsCheck) { - ensure_have_extra (Constants::MAX_INTEGER_DIGIT_COUNT_BASE10); - } - - if (i == 0) { - constexpr char zero[] = "0"; - constexpr size_t zero_len = sizeof(zero) - 1uz; - - append (zero, zero_len); - return; - } - - TChar temp_buf[Constants::MAX_INTEGER_DIGIT_COUNT_BASE10 + 1uz]; - TChar *p = temp_buf + Constants::MAX_INTEGER_DIGIT_COUNT_BASE10; - *p = NUL; - TChar *end = p; - - uint32_t x; - if constexpr (sizeof(Integer) > 4uz) { - uint64_t y; - - if constexpr (std::is_signed_v) { - y = static_cast(i > 0 ? i : -i); - } else { - y = static_cast(i); - } - while (y > std::numeric_limits::max ()) { - *--p = (y % 10) + ZERO; - y /= 10; - } - x = static_cast(y); - } else { - if constexpr (std::is_signed_v) { - x = static_cast(i > 0 ? i : -i); - } else { - x = static_cast(i); - } - } - - while (x > 0) { - *--p = (x % 10) + ZERO; - x /= 10; - } - - if constexpr (std::is_signed_v) { - if (i < 0) - *--p = '-'; - } - - append (p, static_cast(end - p)); - } - - [[gnu::always_inline]] - void ensure_valid_index (size_t access_index) const noexcept - { - if (access_index < idx && access_index < buffer.size ()) [[likely]] { - return; - } - - char *message = nullptr; - int n = asprintf (&message, "Index %zu is out of range (0 - %zu)", access_index, idx); - Helpers::abort_application (n == -1 ? "Index out of range" : message); - } - - [[gnu::always_inline]] - void ensure_have_extra (size_t length) noexcept - { - size_t needed_space = Helpers::add_with_overflow_check (length, idx + 1); - if (needed_space > buffer.size ()) { - char *message = nullptr; - int n = asprintf ( - &message, - "Attempt to store too much data in a buffer (capacity: %zu; exceeded by: %zu)", - buffer.size (), - needed_space - buffer.size () - ); - Helpers::abort_application (n == -1 ? "Attempt to store too much data in a buffer" : message); - } - } - - [[gnu::always_inline]] - void resize_for_extra (size_t needed_space) noexcept - { - if constexpr (TStorage::has_resize) { - size_t required_space = Helpers::add_with_overflow_check (needed_space, idx + 1uz); - size_t current_size = buffer.size (); - if (required_space > current_size) { - size_t new_size = Helpers::add_with_overflow_check (current_size, (current_size / 2uz)); - new_size = Helpers::add_with_overflow_check (new_size, required_space); - buffer.resize (new_size); - } - } - } - - private: - size_t idx; - TStorage buffer; - }; - - template - class static_local_string : public string_base, TChar> - { - using base = string_base, TChar>; - - public: - explicit static_local_string (size_t initial_size = 0uz) noexcept - : base (initial_size) - {} - - explicit static_local_string (const string_segment &token) noexcept - : base (token) - {} - - template - explicit static_local_string (const char (&str)[N]) - : base (N) - { - append (str); - } - }; - - template - class dynamic_local_string : public string_base, TChar> - { - using base = string_base, TChar>; - - public: - explicit dynamic_local_string (size_t initial_size = 0uz) - : base (initial_size) - {} - - explicit dynamic_local_string (const string_segment &token) noexcept - : base (token) - {} - - template - explicit dynamic_local_string (const char (&str)[N]) - : base (N) - { - base::append (str); - } - - explicit dynamic_local_string (std::string_view const& str) - : base (str.length ()) - { - base::append (str); - } - }; - - // Useful aliases - using dynamic_local_property_string = dynamic_local_string; - using dynamic_local_path_string = dynamic_local_string; -} diff --git a/src/native/common/include/shared/cpp-util.hh b/src/native/common/include/shared/cpp-util.hh index 13597ef6afa..11da1bbaa30 100644 --- a/src/native/common/include/shared/cpp-util.hh +++ b/src/native/common/include/shared/cpp-util.hh @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -197,72 +197,8 @@ abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_loc ); } -[[gnu::always_inline, gnu::flatten]] -static inline void -abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_location sloc = std::source_location::current ()) noexcept -{ - abort_unless ( - arg > 0, - [&arg_name, &sloc] { - std::string_view function_name = xamarin::android::detail::get_function_name (sloc.function_name ()); - return xamarin::android::detail::_format_message ( - "%.*s: parameter '%s' must be a positive integer", - static_cast(function_name.length ()), - function_name.data (), - arg_name - ); - }, - sloc - ); -} - namespace xamarin::android { - template - struct CDeleter final - { - using UnderlyingType = std::remove_cv_t; - - void operator() (T* p) - { - UnderlyingType *ptr; - - if constexpr (std::is_const_v) { - ptr = const_cast*> (p); - } else { - ptr = p; - } - - std::free (reinterpret_cast(ptr)); - } - }; - - template - using c_unique_ptr = std::unique_ptr>; - - template - using char_array = std::array; - - template - constexpr auto concat_const (const char (&...parts)[Length]) - { - // `parts` being constant string arrays, Length for each of them includes the trailing NUL byte, thus the - // `sizeof... (Length)` part which subtracts the number of template parameters - the amount of NUL bytes so that - // we don't waste space. - constexpr size_t total_length = (... + Length) - sizeof... (Length); - char_array ret; // lgtm [cpp/paddingbyteinformationdisclosure] the buffer is filled in the loop below - ret[total_length] = 0; - - size_t i = 0uz; - for (char const* from : {parts...}) { - for (; *from != '\0'; i++) { - ret[i] = *from++; - } - } - - return ret; - }; - template concept StringViewPart = std::is_same_v;