libraries/eosiolib/core/eosio/string.hpp
Namespaces
Name |
---|
eosio |
Classes
Name | |
---|---|
class | eosio::string |
Detailed Description
Copyright: defined in eosio.cdt/LICENSE.txt
Source code
#pragma once
#include <cstring> // memcpy, memset, strlen
#include <algorithm> // std::swap
#include <memory> // std::unique_ptr
#include <variant> // std::variant
#include <vector> // std::vector
#include "datastream.hpp" // eosio::datastream
#include "varint.hpp" // eosio::unsigned_int
namespace eosio {
class string {
public:
static constexpr size_t npos = -1;
template <size_t N>
constexpr string(const char (&str)[N])
: _size{N-1}
, _capacity{_size}
, _begin{str}
{
}
constexpr string()
: _size{0}
, _capacity{0}
, _begin{""}
{
}
constexpr string(const char* str, const size_t n)
: _size{n}
, _capacity{_size*2}
{
char* begin{new char[_capacity]};
memcpy(begin, str, _size);
_begin = begin;
}
constexpr string(const size_t n, const char c)
: _size{n}
, _capacity{_size*2}
{
char* begin{new char[_capacity]};
memset(begin, c, _size);
_begin = begin;
}
constexpr string(const string& str, const size_t pos, const size_t n)
: _size{n}
, _capacity{_size*2}
{
if (n == string::npos || str._size < pos+n) {
_size = str._size;
_capacity = _size*2;
}
clone(_size, _capacity, str.data()+pos);
}
constexpr string(const string& str)
: _size{str._size}
, _capacity{str._capacity}
{
if (str.is_literal())
_begin = std::get<const char*>(str._begin);
else
clone(str._size, str._capacity, str.data());
}
constexpr string(string&& str)
: _size{str._size}
, _capacity{str._capacity}
{
if (str.is_literal())
_begin = std::get<const char*>(str._begin);
else
_begin = std::move(std::get<uptr>(str._begin));
}
string& operator=(const string& str) {
if (&str == this)
return *this;
_size = str._size;
_capacity = str._capacity;
if (str.is_literal())
_begin = std::get<const char*>(str._begin);
else
clone(_size, _capacity, str.data());
return *this;
}
string& operator=(string&& str) {
if (&str == this)
return *this;
_size = str._size;
_capacity = str._capacity;
if (str.is_literal())
_begin = std::get<const char*>(str._begin);
else
_begin = std::move(std::get<uptr>(str._begin));
return *this;
}
string& operator=(const char* str) {
_size = strlen(str);
_capacity = _size;
_begin = str;
return *this;
}
char& operator[](const size_t n) {
if (is_literal())
clone(_size, _capacity, std::get<const char*>(_begin));
return std::get<uptr>(_begin).get()[n];
}
const char operator[](const size_t n) const {
return (is_literal()) ? std::get<const char*>(_begin)[n] : std::get<uptr>(_begin).get()[n];
}
char& at(const size_t n) {
eosio::check(0 <= n && n < _size, "eosio::string::at");
return operator[](n);
}
const char at(const size_t n) const {
eosio::check(0 <= n && n < _size, "eosio::string::at const");
return operator[](n);
}
char& front() {
return at(0);
}
const char front() const {
return at(0);
}
char& back() {
return at(_size-1);
}
const char back() const {
return at(_size-1);
}
char* data() {
return begin();
}
const char* data() const {
return cbegin();
}
const char* c_str() const {
static size_t prev_size{0};
char* raw_ptr{nullptr};
if (is_literal())
return std::get<const char*>(_begin);
if (_size == prev_size)
return std::get<uptr>(_begin).get();
else if (_size < prev_size)
raw_ptr = std::get<uptr>(_begin).get();
else {
uptr tmp = std::make_unique<char[]>(_size+1);
raw_ptr = tmp.get();
prev_size = _size;
memcpy(raw_ptr, std::get<uptr>(_begin).get(), _size);
}
raw_ptr[_size+1] = '\0';
return raw_ptr;
}
char* begin() {
if (is_literal()) {
_capacity *= 2;
clone(_size, _capacity, std::get<const char*>(_begin));
}
return std::get<uptr>(_begin).get();
}
const char* cbegin() const {
return (is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get();
}
char* end() {
return begin()+_size;
}
const char* cend() const {
return cbegin()+_size;
}
bool empty() const {
return !_size;
}
size_t size() const {
return _size;
}
size_t length() const {
return _size;
}
size_t capacity() const {
return _capacity;
}
size_t max_size() const {
return npos;
}
void reserve(const size_t n) {
if (_capacity < n) {
_capacity = n;
const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
clone(_size, _capacity, tmp);
}
else
return;
}
void shrink_to_fit() {
_capacity = _size;
}
void clear() {
_size = 0;
if (is_literal())
clone(_size, _capacity, std::get<const char*>(_begin));
std::get<uptr>(_begin).get()[0] = '\0';
}
void resize(const size_t n) {
if (is_literal())
clone(n, _capacity, std::get<const char*>(_begin));
else {
_size = n;
if (n <= _capacity)
memset(std::get<uptr>(_begin).get()+_size, '\0', _capacity-_size);
else {
_capacity = _size*2;
clone(_size, _capacity, std::get<uptr>(_begin).get());
}
}
}
void swap(string& str) {
std::swap(*this, str);
}
void push_back(const char c) {
*this += c;
}
void pop_back() {
if (_size == 0)
return;
resize(--_size);
}
string substr(size_t pos = 0, size_t len = npos) const {
return string(*this, pos, len);
}
size_t copy(char* s, size_t len, size_t pos = 0) const {
eosio::check(pos <= _size, "eosio::string::copy");
len = (_size < pos+len) ? _size : len;
const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
memcpy(s, tmp+pos, len);
return (_size < pos+len) ? _size-pos : len;
}
string& insert(const size_t pos, const char* str) {
return insert(pos, str, strlen(str));
}
string& insert(const size_t pos, const char* str, const size_t len) {
eosio::check((str != nullptr) && (0 <= pos && pos <= _size), "eosio::string::insert");
if (_capacity < (_size+len)) {
_size += len;
_capacity = _size*2;
uptr begin{std::make_unique<char[]>(_capacity)};
const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
memcpy(begin.get(), tmp, pos);
memcpy(begin.get()+pos, str, len);
memcpy(begin.get()+len+pos, tmp+pos, _size-len-pos);
_begin = std::move(begin);
}
else {
if(is_literal())
clone(_size, _capacity, std::get<const char*>(_begin));
_size += len;
memmove(std::get<uptr>(_begin).get()+pos+len, std::get<uptr>(_begin).get()+pos, _size-pos);
memcpy(std::get<uptr>(_begin).get()+pos, str, len);
}
return *this;
}
string& insert(const size_t pos, const string& str) {
insert(pos, str.c_str());
return *this;
}
string& erase(size_t pos = 0, size_t len = npos) {
eosio::check(0 <= pos && pos <= _size, "eosio::string::erase");
if (len == string::npos)
len = _size-pos;
_size -= len;
if (is_literal())
clone(_size, _capacity, std::get<const char*>(_begin));
memmove(std::get<uptr>(_begin).get()+pos+len, std::get<uptr>(_begin).get(), len);
resize(_size);
return *this;
}
string& append(const char* str) {
eosio::check(str != nullptr, "eosio::string::append");
insert(_size, str);
return *this;
}
string& append(const string& str) {
insert(_size, str);
return *this;
}
string& operator+=(const char c) {
if (_capacity == 0) {
_size = 1;
_capacity = 2;
clone(1, _capacity, &c);
}
else if (_size == _capacity) {
_capacity = ++_size*2;
const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
clone(_size, _capacity, tmp);
std::get<uptr>(_begin).get()[_size-1] = c;
}
else
std::get<uptr>(_begin).get()[_size++] = c;
return *this;
}
string& operator+=(const char* rhs) {
append(rhs);
return *this;
}
string& operator+=(const string& rhs) {
append(rhs);
return *this;
}
inline void print() const {
const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
internal_use_do_not_use::prints_l(tmp, _size);
}
friend bool operator< (const string& lhs, const string& rhs);
friend bool operator> (const string& lhs, const string& rhs);
friend bool operator<=(const string& lhs, const string& rhs);
friend bool operator>=(const string& lhs, const string& rhs);
friend bool operator==(const string& lhs, const string& rhs);
friend bool operator!=(const string& lhs, const string& rhs);
friend string operator+ (const string& lhs, const string& rhs);
private:
using uptr = std::unique_ptr<char[]>;
using sso_str = std::variant<const char*, uptr>;
size_t _size = 0;
size_t _capacity = 0;
sso_str _begin = nullptr;
void clone(size_t size, size_t capacity, const char* str) {
_size = size;
_capacity = capacity;
uptr begin{std::make_unique<char[]>(capacity)};
memcpy(begin.get(), str, size);
_begin = std::move(begin);
}
constexpr bool is_literal() const {
return (std::holds_alternative<const char*>(_begin)) ? true : false;
}
};
inline bool operator< (const string& lhs, const string& rhs) {
const char* beg_lhs{lhs.cbegin()}; const char* end_lhs{lhs.cend()};
const char* beg_rhs{rhs.cbegin()}; const char* end_rhs{rhs.cend()};
for(; beg_lhs != end_lhs && beg_rhs != end_rhs; ++beg_lhs, ++beg_rhs) {
if (*beg_lhs < *beg_rhs)
return true;
if (*beg_rhs < *beg_lhs)
return false;
}
return beg_lhs == end_lhs && beg_rhs != end_rhs;
}
inline bool operator> (const string& lhs, const string& rhs) {
return (rhs < lhs);
}
inline bool operator<=(const string& lhs, const string& rhs) {
return !(rhs < lhs);
}
inline bool operator>=(const string& lhs, const string& rhs) {
return !(lhs < rhs);
}
inline bool operator==(const string& lhs, const string& rhs) {
return !(lhs < rhs) && !(rhs < lhs);
}
inline bool operator!=(const string& lhs, const string& rhs) {
return !(lhs == rhs);
}
inline string operator+(const string& lhs, const string& rhs) {
string res{lhs};
res += rhs;
return res;
}
template<typename DataStream>
DataStream& operator<<(DataStream& ds, const string& str) {
ds << unsigned_int(str.size());
if (str.size())
ds.write(str.data(), str.size());
return ds;
}
template<typename DataStream>
DataStream& operator>>(DataStream& ds, string& str) {
std::vector<char> tmp;
ds >> tmp;
str = (tmp.size()) ? string(tmp.data(), tmp.size()) : string();
return ds;
}
} // namespace eosio
Updated on 2022-12-05 at 15:38:08 +0000