#pragma once #if !defined(BAD_APPLE_OS_STRING_INCLUDED) #define BAD_APPLE_OS_STRING_INCLUDED #include #include #include #include namespace std { template class char_traits {}; template<> class char_traits { public: using char_type = char; using int_type = int; using off_type = std::ptrdiff_t; // TODO: should be std::streamoff? // TODO: ?? }; template> // TODO: Allocator class basic_string { public: using traits_type = Traits; using value_type = CharT; using size_type = size_t; using difference_type = ptrdiff_t; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using iterator = pointer; using const_iterator = const_pointer; private: vector _data; public: constexpr basic_string() noexcept : basic_string("") {} constexpr basic_string(const basic_string& other) = default; constexpr basic_string(basic_string&& other) = default; constexpr basic_string(size_type count, value_type chr) : _data(count, chr) {} constexpr basic_string(const basic_string& other, size_type pos, size_type count = npos) : basic_string(other.substr(pos, count)) {} constexpr basic_string(const value_type* str, size_type count) { _data.resize(count + 1); for (size_type idx = 0; idx < count; ++idx) { _data[idx] = str[idx]; } _data[count] = value_type(0); } constexpr basic_string(const value_type* str) : basic_string(str, strlen(str)) {} // NOLINT // TODO: all the other constructors constexpr basic_string& operator=(const basic_string& other) = default; constexpr basic_string& operator=(basic_string&& other) = default; constexpr basic_string& operator=(const value_type* str) { const size_t count = strlen(str); _data.resize(count + 1); for (size_type idx = 0; idx < count; ++idx) { _data[idx] = str[idx]; } _data[count] = value_type(0); return *this; } constexpr basic_string& operator=(value_type chr) { _data.resize(2); _data[0] = chr; _data[1] = value_type(0); return *this; } constexpr basic_string& operator=(std::nullptr_t) = delete; constexpr basic_string& operator+=(value_type chr) noexcept { return append(chr); } constexpr basic_string& operator+=(const basic_string& other) noexcept { return append(other); } [[nodiscard]] constexpr reference operator[](size_type pos) noexcept { return _data[pos]; } [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept { return _data[pos]; } // TODO: the range check should actually also fail for the \0 in the end [[nodiscard]] constexpr reference at(size_type pos) { return _data.at(pos); } [[nodiscard]] constexpr const_reference at(size_type pos) const { return _data.at(pos); } [[nodiscard]] constexpr reference front() noexcept { return _data.front(); } [[nodiscard]] constexpr const_reference front() const noexcept { return _data.front(); } [[nodiscard]] constexpr reference back() noexcept { return _data.at(size() - 1); } [[nodiscard]] constexpr const_reference back() const noexcept { return _data.at(size() - 1); } [[nodiscard]] constexpr pointer data() noexcept { return _data.data(); } [[nodiscard]] constexpr const_pointer data() const noexcept { return _data.data(); } [[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); } [[nodiscard]] constexpr iterator begin() noexcept { return _data.begin(); } [[nodiscard]] constexpr const_iterator begin() const noexcept { return _data.begin(); } [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _data.begin(); } [[nodiscard]] constexpr iterator end() noexcept { return _data.end() - 1; } [[nodiscard]] constexpr const_iterator end() const noexcept { return _data.end() - 1; } [[nodiscard]] constexpr const_iterator cend() const noexcept { return _data.end() - 1; } [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } [[nodiscard]] constexpr size_type size() const noexcept { return _data.size() - 1; } [[nodiscard]] constexpr size_type max_size() const noexcept { return _data.max_size() - 1; } constexpr void reserve(size_type newCapacity) noexcept { _data.reserve(newCapacity + 1); } [[nodiscard]] constexpr size_type capacity() const noexcept { return _data.capacity() - 1; } constexpr void shrink_to_fit() noexcept { _data.shrink_to_fit(); } constexpr void clear() { *this = ""; } constexpr void resize(size_type count, value_type chr = value_type()) { _data.resize(count + 1, chr); _data.back() = value_type(0); } constexpr basic_string& append(value_type chr) noexcept { _data.back() = chr; _data.push_back(value_type()); return *this; } constexpr basic_string& append(const basic_string& other) noexcept { _data.reserve(_data.size() + other.size()); _data.resize(_data.size() - 1); for (char chr : other) { _data.push_back(chr); } _data.push_back(value_type()); return *this; } constexpr void pop_back() noexcept { _data.pop_back(); _data.back() = value_type(); } static inline size_type npos = size_type(-1); }; using string = basic_string; } #endif // !defined(BAD_APPLE_OS_STRING_INCLUDED)