362 lines
9.7 KiB
Plaintext
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 |