diff --git a/CMakeLists.txt b/CMakeLists.txt index 04cb3ea76..e3be2bba7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -349,6 +349,7 @@ set(COMMON src/common/logging/backend.cpp src/common/concepts.h src/common/config.cpp src/common/config.h + src/common/cstring.h src/common/debug.h src/common/disassembler.cpp src/common/disassembler.h diff --git a/src/common/cstring.h b/src/common/cstring.h new file mode 100644 index 000000000..1f3936ee1 --- /dev/null +++ b/src/common/cstring.h @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "assert.h" + +namespace Common { + +/** + * @brief A null-terminated string with a fixed maximum length + * This class is not meant to be used as a general-purpose string class + * It is meant to be used as `char[N]` where memory layout is fixed + * @tparam N Maximum length of the string + * @tparam T Type of character + */ +template +class CString { +public: + class Iterator; + + T data[N]{}; + +public: + CString() = default; + + template + explicit CString(const CString& other) + requires(M <= N) + { + std::ranges::copy(other.begin(), other.end(), data); + } + + void FromString(const std::basic_string_view& str) { + size_t p = str.copy(data, N - 1); + data[p] = '\0'; + } + + void Zero() { + std::ranges::fill(data, 0); + } + + explicit(false) operator std::basic_string_view() const { + return std::basic_string_view{data}; + } + + explicit operator std::basic_string() const { + return std::basic_string{data}; + } + + std::basic_string to_string() const { + return std::basic_string{data}; + } + + std::basic_string_view to_view() const { + return std::basic_string_view{data}; + } + + char* begin() { + return data; + } + + const char* begin() const { + return data; + } + + char* end() { + return data + N; + } + + const char* end() const { + return data + N; + } + + T& operator[](size_t idx) { + return data[idx]; + } + + const T& operator[](size_t idx) const { + return data[idx]; + } + + class Iterator { + T* ptr; + T* end; + + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + using iterator_category = std::random_access_iterator_tag; + + Iterator() = default; + explicit Iterator(T* ptr) : ptr(ptr), end(ptr + N) {} + + Iterator& operator++() { + ++ptr; + return *this; + } + + Iterator operator++(int) { + Iterator tmp = *this; + ++ptr; + return tmp; + } + + operator T*() { + ASSERT_MSG(ptr >= end, "CString iterator out of bounds"); + return ptr; + } + }; +}; +static_assert(sizeof(CString<13>) == sizeof(char[13])); // Ensure size still matches a simple array +static_assert(std::weakly_incrementable::Iterator>); + +} // namespace Common \ No newline at end of file