202 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
 | |
| #pragma once
 | |
| 
 | |
| #if !defined(BAD_APPLE_OS_STRING_INCLUDED)
 | |
| #define BAD_APPLE_OS_STRING_INCLUDED
 | |
| 
 | |
| #include <cstddef>
 | |
| #include <cstring>
 | |
| #include <utility>
 | |
| #include <vector>
 | |
| 
 | |
| namespace std
 | |
| {
 | |
| template<typename CharT>
 | |
| class char_traits {};
 | |
| 
 | |
| template<>
 | |
| class char_traits<char>
 | |
| {
 | |
| public:
 | |
|     using char_type = char;
 | |
|     using int_type = int;
 | |
|     using off_type = std::ptrdiff_t; // TODO: should be std::streamoff?
 | |
|     // TODO: ??
 | |
| };
 | |
| 
 | |
| template<typename CharT, typename Traits = char_traits<CharT>> // 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<value_type> _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);
 | |
|     }
 | |
| 
 | |
|     constexpr bool operator==(const basic_string& other) const noexcept
 | |
|     {
 | |
|         if (size() != other.size()) {
 | |
|             return false;
 | |
|         }
 | |
|         for (size_t idx = 0; idx < size(); ++idx) {
 | |
|             if (at(idx) != other.at(idx)) {
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
|     constexpr bool operator!=(const basic_string& other) const noexcept
 | |
|     {
 | |
|         return !(*this == other); // NOLINT
 | |
|     }
 | |
|     constexpr bool operator==(const value_type* cStr) const noexcept
 | |
|     {
 | |
|         for (value_type chr : *this)
 | |
|         {
 | |
|             if (*cStr == '\0' || chr != *cStr) {
 | |
|                 return false;
 | |
|             }
 | |
|             ++cStr;
 | |
|         }
 | |
|         return true;
 | |
|     }
 | |
|     constexpr bool operator!=(const value_type* cStr) const noexcept
 | |
|     {
 | |
|         return !(*this == cStr); // NOLINT
 | |
|     }
 | |
| 
 | |
|     [[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<char>;
 | |
| 
 | |
| template<typename CharT, typename Traits = char_traits<CharT>> // TODO: Allocator
 | |
| constexpr bool operator==(const CharT* cStr, const basic_string<CharT, Traits>& str) noexcept
 | |
| {
 | |
|     return str == cStr;
 | |
| }
 | |
| 
 | |
| template<typename CharT, typename Traits = char_traits<CharT>> // TODO: Allocator
 | |
| constexpr bool operator!=(const CharT* cStr, const basic_string<CharT, Traits>& str) noexcept
 | |
| {
 | |
|     return str != cStr;
 | |
| }
 | |
| }
 | |
| 
 | |
| #endif // !defined(BAD_APPLE_OS_STRING_INCLUDED)
 |