Files

362 lines
9.7 KiB
Plaintext

#pragma GCC system_header
#ifndef _LIBCXX_STRING
#define _LIBCXX_STRING
#include <__config>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iterator>
#include <memory>
#include <new>
#include <utility>
_LIBCXX_BEGIN_NAMESPACE_STD
static char __null_char = '\0';
template <class CharT>
class char_traits {
public:
using char_type = CharT;
using int_type = int;
using pos_type = int;
using off_type = int;
using state_type = int;
static constexpr void assign(char_type& r, const char_type& a) { r = a; }
static constexpr char_type* assign(char_type* p, size_t count, char_type a)
{
for (size_t sz = 0; sz < count; sz++) {
assign(p[sz], a);
}
return p;
}
static constexpr char_type* move(char_type* dest, const char_type* src, size_t count)
{
for (size_t sz = 0; sz < count; sz++) {
dest[sz] = std::move(src[sz]);
}
return dest;
}
static constexpr size_t length(const char_type* s)
{
return strlen(s);
}
static constexpr char_type* copy(char_type* dest, const char_type* src, size_t count)
{
for (size_t sz = 0; sz < count; sz++) {
dest[sz] = src[sz];
}
return dest;
}
static constexpr int compare(const char_type* a, const char_type* b, size_t count)
{
return strncmp(a, b, count);
}
static constexpr char_type to_char_type(int_type c) { return static_cast<char_type>(c); }
static constexpr int_type to_int_type(char_type c) { return static_cast<int_type>(c); }
static constexpr bool eq_int_type(int_type c1, int_type c2) { return c1 == c2; }
static constexpr int_type eof() { return -1; }
static constexpr bool not_eof(int_type a) { return a != eof(); }
static constexpr bool eq(char_type a, char_type b) { return a == b; }
static constexpr bool lt(char_type a, char_type b) { return a < b; }
};
template <class CharT, class Traits>
class basic_string_view;
template <class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>>
class basic_string {
public:
using value_type = CharT;
using allocator_type = Allocator;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = CharT*;
using const_pointer = const CharT*;
using reference = CharT&;
using const_reference = const CharT&;
using iterator = std::__legacy_iter<pointer>;
using const_iterator = std::__legacy_iter<const_pointer>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
basic_string() = default;
basic_string(const value_type* str)
{
m_size = Traits::length(str);
ensure_capacity(m_size + 1);
Traits::copy(m_str, str, m_size);
Traits::assign(m_str[m_size], '\0');
}
basic_string(const value_type* str, size_t size)
{
m_size = size;
ensure_capacity(m_size + 1);
Traits::copy(m_str, str, m_size);
Traits::assign(m_str[m_size], '\0');
}
template <class Iter>
constexpr basic_string(Iter first, Iter last)
{
m_size = std::distance(first, last);
ensure_capacity(m_size + 1);
for (size_t i = 0; first != last; ++first, ++i) {
Traits::assign(at(i), *first);
}
}
basic_string(const basic_string& s)
{
m_size = s.m_size;
ensure_capacity(m_size + 1);
Traits::copy(m_str, s.m_str, m_size);
Traits::assign(m_str[m_size], '\0');
}
basic_string(basic_string&& s)
{
m_size = s.m_size;
m_capacity = s.m_capacity;
m_str = s.m_str;
s.m_size = s.m_capacity = 0;
s.m_str = &__null_char;
}
~basic_string()
{
clear();
}
basic_string& operator=(const basic_string& s)
{
m_size = s.m_size;
ensure_capacity(m_size + 1);
Traits::copy(m_str, s.m_str, m_size);
Traits::assign(m_str[m_size], '\0');
return *this;
}
basic_string& operator=(basic_string&& s)
{
if (this != &s) {
clear();
m_size = s.m_size;
m_capacity = s.m_capacity;
m_str = s.m_str;
s.m_size = s.m_capacity = 0;
s.m_str = &__null_char;
}
return *this;
}
basic_string& operator+=(const basic_string& s)
{
ensure_capacity(size() + s.size() + 1);
Traits::copy(&m_str[m_size], s.m_str, s.m_size);
m_size += s.size();
Traits::assign(m_str[m_size], '\0');
return *this;
}
basic_string operator+(const basic_string& s) const
{
basic_string res(*this);
res += s;
return res;
}
basic_string operator+(const value_type* s) const
{
basic_string res(*this);
res += basic_string(s);
return res;
}
constexpr allocator_type get_allocator() const { return m_allocator; }
inline void push_back(const value_type& c)
{
ensure_capacity(size() + 2);
Traits::assign(m_str[m_size], c);
m_size++;
Traits::assign(m_str[m_size], '\0');
}
inline void pop_back()
{
--m_size;
Traits::assign(m_str[m_size], '\0');
}
inline const_reference at(size_t i) const
{
return m_str[i];
}
inline reference at(size_t i)
{
return m_str[i];
}
void clear()
{
if (m_capacity && m_str != &__null_char) {
free(m_str);
m_str = &__null_char;
}
m_size = 0;
m_capacity = 0;
}
void resize(size_t count, const value_type& c)
{
ensure_capacity(count + 1);
Traits::assign(&m_str[m_size], count - size(), c);
m_size = count;
Traits::assign(m_str[m_size], '\0');
}
void resize(size_t count) { resize(count, '\0'); }
inline size_t size() const { return m_size; }
inline size_t length() const { return m_size; }
inline bool empty() const { return size() == 0; }
inline const_reference operator[](size_t i) const { return at(i); }
inline reference operator[](size_t i) { return at(i); }
inline const_reference front() const { return at(0); }
inline reference front() { return at(0); }
inline const_reference back() const { return at(size() - 1); }
inline reference back() { return at(size() - 1); }
inline const_pointer c_str() const { return m_str; }
inline const_pointer data() const { return m_str; }
inline iterator begin() { return iterator(&m_str[0]); }
inline iterator end() { return iterator(&m_str[m_size]); }
inline const_iterator cbegin() const { return const_iterator(&m_str[0]); }
inline const_iterator cend() const { return const_iterator(&m_str[m_size]); }
inline reverse_iterator rbegin() { return reverse_iterator(&m_str[m_size - 1]); }
inline reverse_iterator rend() { return reverse_iterator(&m_str[-1]); }
inline const_reverse_iterator crbegin() const { return const_reverse_iterator(&m_str[m_size - 1]); }
inline const_reverse_iterator crend() const { return const_reverse_iterator(&m_str[-1]); }
inline operator std::basic_string_view<CharT, Traits>() const { return std::basic_string_view<CharT, Traits>(data(), size()); }
bool starts_with(value_type c) const
{
if (size() == 0) {
return false;
}
return Traits::eq(at(0), c) == 0;
}
bool starts_with(const value_type* s) const
{
size_t len = Traits::length(s);
if (size() < len) {
return false;
}
return Traits::compare(c_str(), s, len) == 0;
}
private:
inline void ensure_capacity(size_t new_size)
{
int capacity = 4;
while (new_size > capacity) {
capacity *= 2;
}
grow(capacity);
}
void grow(size_t capacity)
{
if (capacity < m_capacity) {
return;
}
if (!m_capacity) {
m_str = m_allocator.allocate(capacity);
} else {
auto new_str = m_allocator.allocate(capacity);
Traits::move(new_str, m_str, m_capacity);
m_allocator.deallocate(m_str, m_capacity);
m_str = new_str;
}
m_capacity = capacity;
}
size_t m_size { 0 };
size_t m_capacity { 0 };
value_type* m_str { &__null_char };
allocator_type m_allocator;
};
typedef basic_string<char> string;
static std::string to_string(int a)
{
char buf[32];
std::sprintf(buf, "%d", a);
return std::string(buf);
}
static std::string to_string(unsigned a)
{
char buf[32];
std::sprintf(buf, "%u", a);
return std::string(buf);
}
template <class CharT, class Traits, class Allocator>
bool operator==(const std::basic_string<CharT, Traits, Allocator>& a, const std::basic_string<CharT, Traits, Allocator>& b)
{
if (a.size() != b.size()) {
return false;
}
return Traits::compare(a.c_str(), b.c_str(), a.size()) == 0;
}
template <class CharT, class Traits, class Allocator>
bool operator==(const std::basic_string<CharT, Traits, Allocator>& a, const CharT* cstr)
{
size_t bsize = Traits::length(cstr);
if (a.size() != bsize) {
return false;
}
return Traits::compare(a.c_str(), cstr, a.size()) == 0;
}
template <class CharT, class Traits, class Allocator>
bool operator<(const std::basic_string<CharT, Traits, Allocator>& a, const std::basic_string<CharT, Traits, Allocator>& b)
{
int eq = Traits::compare(a.c_str(), b.c_str(), std::min(a.size(), b.size()));
if (!eq) {
return eq == -1;
}
return a.size() < b.size();
}
_LIBCXX_END_NAMESPACE_STD
#endif // _LIBCXX_STRING