C++ implementation of basic_string












0












$begingroup$


This is a basic_string implementation that has SSO. It's not done, but the fundamental operations are all there (append, erase, resize, reserve, push_back/pop_back). Proper iterators and my own char_traits impl will be added eventually.



#include <string>

template<typename CharType, typename Traits = std::char_traits<CharType>, typename Allocator = std::allocator<CharType>>
class kbasic_string
{
public:
static const size_t npos = -1;
using iterator = CharType*;
using const_iterator = const CharType*;

friend kbasic_string operator+(const kbasic_string& lhs, const kbasic_string& rhs)
{
return kbasic_string{lhs}.append(rhs);
}

friend kbasic_string operator+(const kbasic_string& lhs, const CharType* rhs)
{
return kbasic_string{lhs}.append(rhs);
}

friend kbasic_string operator+(const kbasic_string& lhs, CharType rhs)
{
return kbasic_string{lhs}.append(rhs);
}

friend std::ostream& operator<<(std::ostream& lhs, const kbasic_string& rhs)
{
lhs.write(rhs.data(), rhs.size());
return lhs;
}

friend std::wostream& operator<<(std::wostream& lhs, const kbasic_string& rhs)
{
lhs.write(rhs.data(), rhs.size());
return lhs;
}

kbasic_string() = default;

kbasic_string(const kbasic_string& other)
{
reserve(other.capacity_);
if (other.size_)
std::copy(other.begin(), other.end() + 1, begin());
size_ = other.size_;
}

kbasic_string(kbasic_string&& other)
{
if (other.on_heap())
{
std::memcpy(&data_, &other.data_, sizeof(CharType*));
std::memset(&other.data_, 0, sizeof(CharType*));
}
else
{
std::copy(other.begin(), other.end() + 1, begin());
}
size_ = other.size_;
capacity_ = other.capacity_;
on_heap_ = other.on_heap_;
other.on_heap_ = false;
}

kbasic_string& operator=(const kbasic_string& other)
{
reserve(other.capacity_);
if (other.size_)
std::copy(other.begin(), other.end() + 1, begin());
size_ = other.size_;
return *this;
}

kbasic_string& operator=(kbasic_string&& other)
{
if (other.on_heap())
{
std::memcpy(&data_, &other.data_, sizeof(CharType*));
std::memset(&other.data_, 0, sizeof(CharType*));
on_heap_ = true;
}
else
{
std::copy(other.begin(), other.end() + 1, begin());
}
size_ = other.size_;
capacity_ = other.capacity_;
other.on_heap_ = false;
return *this;
}

kbasic_string(const CharType* str)
{
size_t size = Traits::length(str);
if (size > capacity_)
reserve(size);
std::copy(str, str + size + 1, data());
size_ = size;
}

kbasic_string& operator=(const CharType* str)
{
size_t size = Traits::length(str);
if (size > capacity_)
reserve(size);
std::copy(str, str + size + 1, data());
size_ = size;
}

void reserve(size_t capacity)
{
if (capacity <= capacity_ || capacity <= 22)
return;
Allocator alloc;
CharType* mem = alloc.allocate(capacity + 1);
if (size_)
std::copy(begin(), end() + 1, mem);
if (on_heap())
alloc.deallocate(data(), capacity_ + 1);
else
on_heap_ = true;
std::memcpy(data_, &mem, sizeof(CharType*));
capacity_ = capacity;
}

void resize(size_t size, CharType app)
{
if (size > size_)
{
reserve(size);
std::fill(end(), end() + (size - size_), app);
*(end() + (size - size_) + 1) = 0;
}
else if (size < size_)
{
erase(end() - (size_ - size), end());
}
else
{
return;
}
size_ = size;
}

void resize(size_t size)
{
resize(size, 0);
}

template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
kbasic_string& erase(Iter first, Iter last)
{
return erase(first - begin(), last - first);
}

kbasic_string& erase(size_t pos, size_t count)
{
if (pos > size_)
throw std::out_of_range("pos is out of range");
std::copy(begin() + pos + count, end() + 1, begin() + pos);
size_ -= count;
return *this;
}

template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
kbasic_string& erase(Iter it)
{
return erase(it - begin(), 1);
}

void pop_back()
{
erase(end() - 1);
}

void clear()
{
erase(begin(), end());
}

kbasic_string& append(const CharType* str, size_t len)
{
if (size_ + len > capacity_)
reserve(size_ + len);
std::copy(str, str + len + 1, begin() + size_);
size_ += len;
return *this;
}

kbasic_string& append(const CharType* str)
{
return append(str, Traits::length(str));
}

kbasic_string& append(const kbasic_string& str)
{
return append(str.data());
}

kbasic_string& append(CharType ch)
{
if (size_ + 1 > capacity_)
reserve(size_ + 1);
iterator prev_end = begin() + size_;
*prev_end = ch;
*(prev_end + 1) = 0;
++size_;
return *this;
}

template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
kbasic_string& append(Iter first, Iter last)
{
if (last - first > capacity_)
reserve(last - first);
std::copy(first, last, begin() + size_);
return *this;
}

void push_back(CharType ch)
{
append(ch);
}

CharType* data() noexcept
{
return on_heap() ? heap_ptr() : data_;
}

const CharType* data() const noexcept
{
return on_heap() ? heap_ptr() : data_;
}

size_t size() const noexcept
{
return size_;
}

size_t length() const noexcept
{
return size_;
}

size_t capacity() const noexcept
{
return capacity_;
}

iterator begin() noexcept
{
return data();
}

const_iterator begin() const noexcept
{
return data();
}

iterator end() noexcept
{
return data() + size_;
}

const_iterator end() const noexcept
{
return data() + size_;
}

bool empty() const noexcept
{
return !size_;
}

CharType& at(size_t n)
{
return data()[n];
}

const CharType& at(size_t n) const
{
return data()[n];
}

CharType& operator(size_t n)
{
return at(n);
}

const CharType& operator(size_t n) const
{
return at(n);
}

kbasic_string& operator+=(const kbasic_string& other)
{
return append(other);
}

kbasic_string& operator+=(const CharType* str)
{
return append(str);
}
kbasic_string& operator+=(CharType ch)
{
return append(ch);
}

bool operator==(const kbasic_string& other)
{
return std::equal(begin(), end(), other.begin(), other.end());
}

bool operator==(const CharType* str)
{
return std::equal(begin(), end(), str, str + Traits::length(str));
}

bool operator==(CharType ch)
{
return size_ == 1 && *begin() == ch;
}

bool operator!=(const kbasic_string& other)
{
return !(*this == other);
}

bool operator!=(const CharType* str)
{
return !(*this == str);
}

bool operator!=(CharType ch)
{
return !(*this == ch);
}

~kbasic_string()
{
if (on_heap())
Allocator{}.deallocate(data(), capacity_ + 1);
}

private:
bool on_heap() const
{
return on_heap_;
}

const CharType* heap_ptr() const
{
CharType* ptr = nullptr;
std::memcpy(&ptr, data_, sizeof(CharType*));
return ptr;
}

CharType* heap_ptr()
{
CharType* ptr = nullptr;
std::memcpy(&ptr, data_, sizeof(CharType*));
return ptr;
}

size_t size_ = 0;
size_t capacity_ = 22;
bool on_heap_ = false;
CharType data_[23] = {0};
};









share|improve this question









New contributor




Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$

















    0












    $begingroup$


    This is a basic_string implementation that has SSO. It's not done, but the fundamental operations are all there (append, erase, resize, reserve, push_back/pop_back). Proper iterators and my own char_traits impl will be added eventually.



    #include <string>

    template<typename CharType, typename Traits = std::char_traits<CharType>, typename Allocator = std::allocator<CharType>>
    class kbasic_string
    {
    public:
    static const size_t npos = -1;
    using iterator = CharType*;
    using const_iterator = const CharType*;

    friend kbasic_string operator+(const kbasic_string& lhs, const kbasic_string& rhs)
    {
    return kbasic_string{lhs}.append(rhs);
    }

    friend kbasic_string operator+(const kbasic_string& lhs, const CharType* rhs)
    {
    return kbasic_string{lhs}.append(rhs);
    }

    friend kbasic_string operator+(const kbasic_string& lhs, CharType rhs)
    {
    return kbasic_string{lhs}.append(rhs);
    }

    friend std::ostream& operator<<(std::ostream& lhs, const kbasic_string& rhs)
    {
    lhs.write(rhs.data(), rhs.size());
    return lhs;
    }

    friend std::wostream& operator<<(std::wostream& lhs, const kbasic_string& rhs)
    {
    lhs.write(rhs.data(), rhs.size());
    return lhs;
    }

    kbasic_string() = default;

    kbasic_string(const kbasic_string& other)
    {
    reserve(other.capacity_);
    if (other.size_)
    std::copy(other.begin(), other.end() + 1, begin());
    size_ = other.size_;
    }

    kbasic_string(kbasic_string&& other)
    {
    if (other.on_heap())
    {
    std::memcpy(&data_, &other.data_, sizeof(CharType*));
    std::memset(&other.data_, 0, sizeof(CharType*));
    }
    else
    {
    std::copy(other.begin(), other.end() + 1, begin());
    }
    size_ = other.size_;
    capacity_ = other.capacity_;
    on_heap_ = other.on_heap_;
    other.on_heap_ = false;
    }

    kbasic_string& operator=(const kbasic_string& other)
    {
    reserve(other.capacity_);
    if (other.size_)
    std::copy(other.begin(), other.end() + 1, begin());
    size_ = other.size_;
    return *this;
    }

    kbasic_string& operator=(kbasic_string&& other)
    {
    if (other.on_heap())
    {
    std::memcpy(&data_, &other.data_, sizeof(CharType*));
    std::memset(&other.data_, 0, sizeof(CharType*));
    on_heap_ = true;
    }
    else
    {
    std::copy(other.begin(), other.end() + 1, begin());
    }
    size_ = other.size_;
    capacity_ = other.capacity_;
    other.on_heap_ = false;
    return *this;
    }

    kbasic_string(const CharType* str)
    {
    size_t size = Traits::length(str);
    if (size > capacity_)
    reserve(size);
    std::copy(str, str + size + 1, data());
    size_ = size;
    }

    kbasic_string& operator=(const CharType* str)
    {
    size_t size = Traits::length(str);
    if (size > capacity_)
    reserve(size);
    std::copy(str, str + size + 1, data());
    size_ = size;
    }

    void reserve(size_t capacity)
    {
    if (capacity <= capacity_ || capacity <= 22)
    return;
    Allocator alloc;
    CharType* mem = alloc.allocate(capacity + 1);
    if (size_)
    std::copy(begin(), end() + 1, mem);
    if (on_heap())
    alloc.deallocate(data(), capacity_ + 1);
    else
    on_heap_ = true;
    std::memcpy(data_, &mem, sizeof(CharType*));
    capacity_ = capacity;
    }

    void resize(size_t size, CharType app)
    {
    if (size > size_)
    {
    reserve(size);
    std::fill(end(), end() + (size - size_), app);
    *(end() + (size - size_) + 1) = 0;
    }
    else if (size < size_)
    {
    erase(end() - (size_ - size), end());
    }
    else
    {
    return;
    }
    size_ = size;
    }

    void resize(size_t size)
    {
    resize(size, 0);
    }

    template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
    kbasic_string& erase(Iter first, Iter last)
    {
    return erase(first - begin(), last - first);
    }

    kbasic_string& erase(size_t pos, size_t count)
    {
    if (pos > size_)
    throw std::out_of_range("pos is out of range");
    std::copy(begin() + pos + count, end() + 1, begin() + pos);
    size_ -= count;
    return *this;
    }

    template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
    kbasic_string& erase(Iter it)
    {
    return erase(it - begin(), 1);
    }

    void pop_back()
    {
    erase(end() - 1);
    }

    void clear()
    {
    erase(begin(), end());
    }

    kbasic_string& append(const CharType* str, size_t len)
    {
    if (size_ + len > capacity_)
    reserve(size_ + len);
    std::copy(str, str + len + 1, begin() + size_);
    size_ += len;
    return *this;
    }

    kbasic_string& append(const CharType* str)
    {
    return append(str, Traits::length(str));
    }

    kbasic_string& append(const kbasic_string& str)
    {
    return append(str.data());
    }

    kbasic_string& append(CharType ch)
    {
    if (size_ + 1 > capacity_)
    reserve(size_ + 1);
    iterator prev_end = begin() + size_;
    *prev_end = ch;
    *(prev_end + 1) = 0;
    ++size_;
    return *this;
    }

    template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
    kbasic_string& append(Iter first, Iter last)
    {
    if (last - first > capacity_)
    reserve(last - first);
    std::copy(first, last, begin() + size_);
    return *this;
    }

    void push_back(CharType ch)
    {
    append(ch);
    }

    CharType* data() noexcept
    {
    return on_heap() ? heap_ptr() : data_;
    }

    const CharType* data() const noexcept
    {
    return on_heap() ? heap_ptr() : data_;
    }

    size_t size() const noexcept
    {
    return size_;
    }

    size_t length() const noexcept
    {
    return size_;
    }

    size_t capacity() const noexcept
    {
    return capacity_;
    }

    iterator begin() noexcept
    {
    return data();
    }

    const_iterator begin() const noexcept
    {
    return data();
    }

    iterator end() noexcept
    {
    return data() + size_;
    }

    const_iterator end() const noexcept
    {
    return data() + size_;
    }

    bool empty() const noexcept
    {
    return !size_;
    }

    CharType& at(size_t n)
    {
    return data()[n];
    }

    const CharType& at(size_t n) const
    {
    return data()[n];
    }

    CharType& operator(size_t n)
    {
    return at(n);
    }

    const CharType& operator(size_t n) const
    {
    return at(n);
    }

    kbasic_string& operator+=(const kbasic_string& other)
    {
    return append(other);
    }

    kbasic_string& operator+=(const CharType* str)
    {
    return append(str);
    }
    kbasic_string& operator+=(CharType ch)
    {
    return append(ch);
    }

    bool operator==(const kbasic_string& other)
    {
    return std::equal(begin(), end(), other.begin(), other.end());
    }

    bool operator==(const CharType* str)
    {
    return std::equal(begin(), end(), str, str + Traits::length(str));
    }

    bool operator==(CharType ch)
    {
    return size_ == 1 && *begin() == ch;
    }

    bool operator!=(const kbasic_string& other)
    {
    return !(*this == other);
    }

    bool operator!=(const CharType* str)
    {
    return !(*this == str);
    }

    bool operator!=(CharType ch)
    {
    return !(*this == ch);
    }

    ~kbasic_string()
    {
    if (on_heap())
    Allocator{}.deallocate(data(), capacity_ + 1);
    }

    private:
    bool on_heap() const
    {
    return on_heap_;
    }

    const CharType* heap_ptr() const
    {
    CharType* ptr = nullptr;
    std::memcpy(&ptr, data_, sizeof(CharType*));
    return ptr;
    }

    CharType* heap_ptr()
    {
    CharType* ptr = nullptr;
    std::memcpy(&ptr, data_, sizeof(CharType*));
    return ptr;
    }

    size_t size_ = 0;
    size_t capacity_ = 22;
    bool on_heap_ = false;
    CharType data_[23] = {0};
    };









    share|improve this question









    New contributor




    Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$















      0












      0








      0





      $begingroup$


      This is a basic_string implementation that has SSO. It's not done, but the fundamental operations are all there (append, erase, resize, reserve, push_back/pop_back). Proper iterators and my own char_traits impl will be added eventually.



      #include <string>

      template<typename CharType, typename Traits = std::char_traits<CharType>, typename Allocator = std::allocator<CharType>>
      class kbasic_string
      {
      public:
      static const size_t npos = -1;
      using iterator = CharType*;
      using const_iterator = const CharType*;

      friend kbasic_string operator+(const kbasic_string& lhs, const kbasic_string& rhs)
      {
      return kbasic_string{lhs}.append(rhs);
      }

      friend kbasic_string operator+(const kbasic_string& lhs, const CharType* rhs)
      {
      return kbasic_string{lhs}.append(rhs);
      }

      friend kbasic_string operator+(const kbasic_string& lhs, CharType rhs)
      {
      return kbasic_string{lhs}.append(rhs);
      }

      friend std::ostream& operator<<(std::ostream& lhs, const kbasic_string& rhs)
      {
      lhs.write(rhs.data(), rhs.size());
      return lhs;
      }

      friend std::wostream& operator<<(std::wostream& lhs, const kbasic_string& rhs)
      {
      lhs.write(rhs.data(), rhs.size());
      return lhs;
      }

      kbasic_string() = default;

      kbasic_string(const kbasic_string& other)
      {
      reserve(other.capacity_);
      if (other.size_)
      std::copy(other.begin(), other.end() + 1, begin());
      size_ = other.size_;
      }

      kbasic_string(kbasic_string&& other)
      {
      if (other.on_heap())
      {
      std::memcpy(&data_, &other.data_, sizeof(CharType*));
      std::memset(&other.data_, 0, sizeof(CharType*));
      }
      else
      {
      std::copy(other.begin(), other.end() + 1, begin());
      }
      size_ = other.size_;
      capacity_ = other.capacity_;
      on_heap_ = other.on_heap_;
      other.on_heap_ = false;
      }

      kbasic_string& operator=(const kbasic_string& other)
      {
      reserve(other.capacity_);
      if (other.size_)
      std::copy(other.begin(), other.end() + 1, begin());
      size_ = other.size_;
      return *this;
      }

      kbasic_string& operator=(kbasic_string&& other)
      {
      if (other.on_heap())
      {
      std::memcpy(&data_, &other.data_, sizeof(CharType*));
      std::memset(&other.data_, 0, sizeof(CharType*));
      on_heap_ = true;
      }
      else
      {
      std::copy(other.begin(), other.end() + 1, begin());
      }
      size_ = other.size_;
      capacity_ = other.capacity_;
      other.on_heap_ = false;
      return *this;
      }

      kbasic_string(const CharType* str)
      {
      size_t size = Traits::length(str);
      if (size > capacity_)
      reserve(size);
      std::copy(str, str + size + 1, data());
      size_ = size;
      }

      kbasic_string& operator=(const CharType* str)
      {
      size_t size = Traits::length(str);
      if (size > capacity_)
      reserve(size);
      std::copy(str, str + size + 1, data());
      size_ = size;
      }

      void reserve(size_t capacity)
      {
      if (capacity <= capacity_ || capacity <= 22)
      return;
      Allocator alloc;
      CharType* mem = alloc.allocate(capacity + 1);
      if (size_)
      std::copy(begin(), end() + 1, mem);
      if (on_heap())
      alloc.deallocate(data(), capacity_ + 1);
      else
      on_heap_ = true;
      std::memcpy(data_, &mem, sizeof(CharType*));
      capacity_ = capacity;
      }

      void resize(size_t size, CharType app)
      {
      if (size > size_)
      {
      reserve(size);
      std::fill(end(), end() + (size - size_), app);
      *(end() + (size - size_) + 1) = 0;
      }
      else if (size < size_)
      {
      erase(end() - (size_ - size), end());
      }
      else
      {
      return;
      }
      size_ = size;
      }

      void resize(size_t size)
      {
      resize(size, 0);
      }

      template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
      kbasic_string& erase(Iter first, Iter last)
      {
      return erase(first - begin(), last - first);
      }

      kbasic_string& erase(size_t pos, size_t count)
      {
      if (pos > size_)
      throw std::out_of_range("pos is out of range");
      std::copy(begin() + pos + count, end() + 1, begin() + pos);
      size_ -= count;
      return *this;
      }

      template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
      kbasic_string& erase(Iter it)
      {
      return erase(it - begin(), 1);
      }

      void pop_back()
      {
      erase(end() - 1);
      }

      void clear()
      {
      erase(begin(), end());
      }

      kbasic_string& append(const CharType* str, size_t len)
      {
      if (size_ + len > capacity_)
      reserve(size_ + len);
      std::copy(str, str + len + 1, begin() + size_);
      size_ += len;
      return *this;
      }

      kbasic_string& append(const CharType* str)
      {
      return append(str, Traits::length(str));
      }

      kbasic_string& append(const kbasic_string& str)
      {
      return append(str.data());
      }

      kbasic_string& append(CharType ch)
      {
      if (size_ + 1 > capacity_)
      reserve(size_ + 1);
      iterator prev_end = begin() + size_;
      *prev_end = ch;
      *(prev_end + 1) = 0;
      ++size_;
      return *this;
      }

      template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
      kbasic_string& append(Iter first, Iter last)
      {
      if (last - first > capacity_)
      reserve(last - first);
      std::copy(first, last, begin() + size_);
      return *this;
      }

      void push_back(CharType ch)
      {
      append(ch);
      }

      CharType* data() noexcept
      {
      return on_heap() ? heap_ptr() : data_;
      }

      const CharType* data() const noexcept
      {
      return on_heap() ? heap_ptr() : data_;
      }

      size_t size() const noexcept
      {
      return size_;
      }

      size_t length() const noexcept
      {
      return size_;
      }

      size_t capacity() const noexcept
      {
      return capacity_;
      }

      iterator begin() noexcept
      {
      return data();
      }

      const_iterator begin() const noexcept
      {
      return data();
      }

      iterator end() noexcept
      {
      return data() + size_;
      }

      const_iterator end() const noexcept
      {
      return data() + size_;
      }

      bool empty() const noexcept
      {
      return !size_;
      }

      CharType& at(size_t n)
      {
      return data()[n];
      }

      const CharType& at(size_t n) const
      {
      return data()[n];
      }

      CharType& operator(size_t n)
      {
      return at(n);
      }

      const CharType& operator(size_t n) const
      {
      return at(n);
      }

      kbasic_string& operator+=(const kbasic_string& other)
      {
      return append(other);
      }

      kbasic_string& operator+=(const CharType* str)
      {
      return append(str);
      }
      kbasic_string& operator+=(CharType ch)
      {
      return append(ch);
      }

      bool operator==(const kbasic_string& other)
      {
      return std::equal(begin(), end(), other.begin(), other.end());
      }

      bool operator==(const CharType* str)
      {
      return std::equal(begin(), end(), str, str + Traits::length(str));
      }

      bool operator==(CharType ch)
      {
      return size_ == 1 && *begin() == ch;
      }

      bool operator!=(const kbasic_string& other)
      {
      return !(*this == other);
      }

      bool operator!=(const CharType* str)
      {
      return !(*this == str);
      }

      bool operator!=(CharType ch)
      {
      return !(*this == ch);
      }

      ~kbasic_string()
      {
      if (on_heap())
      Allocator{}.deallocate(data(), capacity_ + 1);
      }

      private:
      bool on_heap() const
      {
      return on_heap_;
      }

      const CharType* heap_ptr() const
      {
      CharType* ptr = nullptr;
      std::memcpy(&ptr, data_, sizeof(CharType*));
      return ptr;
      }

      CharType* heap_ptr()
      {
      CharType* ptr = nullptr;
      std::memcpy(&ptr, data_, sizeof(CharType*));
      return ptr;
      }

      size_t size_ = 0;
      size_t capacity_ = 22;
      bool on_heap_ = false;
      CharType data_[23] = {0};
      };









      share|improve this question









      New contributor




      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      This is a basic_string implementation that has SSO. It's not done, but the fundamental operations are all there (append, erase, resize, reserve, push_back/pop_back). Proper iterators and my own char_traits impl will be added eventually.



      #include <string>

      template<typename CharType, typename Traits = std::char_traits<CharType>, typename Allocator = std::allocator<CharType>>
      class kbasic_string
      {
      public:
      static const size_t npos = -1;
      using iterator = CharType*;
      using const_iterator = const CharType*;

      friend kbasic_string operator+(const kbasic_string& lhs, const kbasic_string& rhs)
      {
      return kbasic_string{lhs}.append(rhs);
      }

      friend kbasic_string operator+(const kbasic_string& lhs, const CharType* rhs)
      {
      return kbasic_string{lhs}.append(rhs);
      }

      friend kbasic_string operator+(const kbasic_string& lhs, CharType rhs)
      {
      return kbasic_string{lhs}.append(rhs);
      }

      friend std::ostream& operator<<(std::ostream& lhs, const kbasic_string& rhs)
      {
      lhs.write(rhs.data(), rhs.size());
      return lhs;
      }

      friend std::wostream& operator<<(std::wostream& lhs, const kbasic_string& rhs)
      {
      lhs.write(rhs.data(), rhs.size());
      return lhs;
      }

      kbasic_string() = default;

      kbasic_string(const kbasic_string& other)
      {
      reserve(other.capacity_);
      if (other.size_)
      std::copy(other.begin(), other.end() + 1, begin());
      size_ = other.size_;
      }

      kbasic_string(kbasic_string&& other)
      {
      if (other.on_heap())
      {
      std::memcpy(&data_, &other.data_, sizeof(CharType*));
      std::memset(&other.data_, 0, sizeof(CharType*));
      }
      else
      {
      std::copy(other.begin(), other.end() + 1, begin());
      }
      size_ = other.size_;
      capacity_ = other.capacity_;
      on_heap_ = other.on_heap_;
      other.on_heap_ = false;
      }

      kbasic_string& operator=(const kbasic_string& other)
      {
      reserve(other.capacity_);
      if (other.size_)
      std::copy(other.begin(), other.end() + 1, begin());
      size_ = other.size_;
      return *this;
      }

      kbasic_string& operator=(kbasic_string&& other)
      {
      if (other.on_heap())
      {
      std::memcpy(&data_, &other.data_, sizeof(CharType*));
      std::memset(&other.data_, 0, sizeof(CharType*));
      on_heap_ = true;
      }
      else
      {
      std::copy(other.begin(), other.end() + 1, begin());
      }
      size_ = other.size_;
      capacity_ = other.capacity_;
      other.on_heap_ = false;
      return *this;
      }

      kbasic_string(const CharType* str)
      {
      size_t size = Traits::length(str);
      if (size > capacity_)
      reserve(size);
      std::copy(str, str + size + 1, data());
      size_ = size;
      }

      kbasic_string& operator=(const CharType* str)
      {
      size_t size = Traits::length(str);
      if (size > capacity_)
      reserve(size);
      std::copy(str, str + size + 1, data());
      size_ = size;
      }

      void reserve(size_t capacity)
      {
      if (capacity <= capacity_ || capacity <= 22)
      return;
      Allocator alloc;
      CharType* mem = alloc.allocate(capacity + 1);
      if (size_)
      std::copy(begin(), end() + 1, mem);
      if (on_heap())
      alloc.deallocate(data(), capacity_ + 1);
      else
      on_heap_ = true;
      std::memcpy(data_, &mem, sizeof(CharType*));
      capacity_ = capacity;
      }

      void resize(size_t size, CharType app)
      {
      if (size > size_)
      {
      reserve(size);
      std::fill(end(), end() + (size - size_), app);
      *(end() + (size - size_) + 1) = 0;
      }
      else if (size < size_)
      {
      erase(end() - (size_ - size), end());
      }
      else
      {
      return;
      }
      size_ = size;
      }

      void resize(size_t size)
      {
      resize(size, 0);
      }

      template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
      kbasic_string& erase(Iter first, Iter last)
      {
      return erase(first - begin(), last - first);
      }

      kbasic_string& erase(size_t pos, size_t count)
      {
      if (pos > size_)
      throw std::out_of_range("pos is out of range");
      std::copy(begin() + pos + count, end() + 1, begin() + pos);
      size_ -= count;
      return *this;
      }

      template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
      kbasic_string& erase(Iter it)
      {
      return erase(it - begin(), 1);
      }

      void pop_back()
      {
      erase(end() - 1);
      }

      void clear()
      {
      erase(begin(), end());
      }

      kbasic_string& append(const CharType* str, size_t len)
      {
      if (size_ + len > capacity_)
      reserve(size_ + len);
      std::copy(str, str + len + 1, begin() + size_);
      size_ += len;
      return *this;
      }

      kbasic_string& append(const CharType* str)
      {
      return append(str, Traits::length(str));
      }

      kbasic_string& append(const kbasic_string& str)
      {
      return append(str.data());
      }

      kbasic_string& append(CharType ch)
      {
      if (size_ + 1 > capacity_)
      reserve(size_ + 1);
      iterator prev_end = begin() + size_;
      *prev_end = ch;
      *(prev_end + 1) = 0;
      ++size_;
      return *this;
      }

      template<typename Iter, typename = std::enable_if_t<std::_Is_iterator_v<Iter>>>
      kbasic_string& append(Iter first, Iter last)
      {
      if (last - first > capacity_)
      reserve(last - first);
      std::copy(first, last, begin() + size_);
      return *this;
      }

      void push_back(CharType ch)
      {
      append(ch);
      }

      CharType* data() noexcept
      {
      return on_heap() ? heap_ptr() : data_;
      }

      const CharType* data() const noexcept
      {
      return on_heap() ? heap_ptr() : data_;
      }

      size_t size() const noexcept
      {
      return size_;
      }

      size_t length() const noexcept
      {
      return size_;
      }

      size_t capacity() const noexcept
      {
      return capacity_;
      }

      iterator begin() noexcept
      {
      return data();
      }

      const_iterator begin() const noexcept
      {
      return data();
      }

      iterator end() noexcept
      {
      return data() + size_;
      }

      const_iterator end() const noexcept
      {
      return data() + size_;
      }

      bool empty() const noexcept
      {
      return !size_;
      }

      CharType& at(size_t n)
      {
      return data()[n];
      }

      const CharType& at(size_t n) const
      {
      return data()[n];
      }

      CharType& operator(size_t n)
      {
      return at(n);
      }

      const CharType& operator(size_t n) const
      {
      return at(n);
      }

      kbasic_string& operator+=(const kbasic_string& other)
      {
      return append(other);
      }

      kbasic_string& operator+=(const CharType* str)
      {
      return append(str);
      }
      kbasic_string& operator+=(CharType ch)
      {
      return append(ch);
      }

      bool operator==(const kbasic_string& other)
      {
      return std::equal(begin(), end(), other.begin(), other.end());
      }

      bool operator==(const CharType* str)
      {
      return std::equal(begin(), end(), str, str + Traits::length(str));
      }

      bool operator==(CharType ch)
      {
      return size_ == 1 && *begin() == ch;
      }

      bool operator!=(const kbasic_string& other)
      {
      return !(*this == other);
      }

      bool operator!=(const CharType* str)
      {
      return !(*this == str);
      }

      bool operator!=(CharType ch)
      {
      return !(*this == ch);
      }

      ~kbasic_string()
      {
      if (on_heap())
      Allocator{}.deallocate(data(), capacity_ + 1);
      }

      private:
      bool on_heap() const
      {
      return on_heap_;
      }

      const CharType* heap_ptr() const
      {
      CharType* ptr = nullptr;
      std::memcpy(&ptr, data_, sizeof(CharType*));
      return ptr;
      }

      CharType* heap_ptr()
      {
      CharType* ptr = nullptr;
      std::memcpy(&ptr, data_, sizeof(CharType*));
      return ptr;
      }

      size_t size_ = 0;
      size_t capacity_ = 22;
      bool on_heap_ = false;
      CharType data_[23] = {0};
      };






      c++ strings






      share|improve this question









      New contributor




      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 2 hours ago









      Jamal

      30.3k11116226




      30.3k11116226






      New contributor




      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 hours ago









      Krystian SKrystian S

      101




      101




      New contributor




      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Krystian S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          0






          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          Krystian S is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211515%2fc-implementation-of-basic-string%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          Krystian S is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          Krystian S is a new contributor. Be nice, and check out our Code of Conduct.













          Krystian S is a new contributor. Be nice, and check out our Code of Conduct.












          Krystian S is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211515%2fc-implementation-of-basic-string%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

          is 'sed' thread safe

          How to make a Squid Proxy server?