C++ String Class Implementation: Cadena.hpp and Cadena.cpp

C++ String Class Implementation: Cadena

cadena.hpp


#ifndef CADENA_HPP_
#define CADENA_HPP_

#include <iostream>
#include <cstring>
#include <stdexcept>
#include <cctype>
#include <iterator>

class Cadena {
private:
    static char vacia[1];
    size_t tam_;
    char* s_;
public:
    // Constructors
    explicit Cadena(int t = 0, char s = ' ');
    Cadena(const char* c);
    Cadena(const Cadena& c);
    Cadena(Cadena&& c);

    // Operator Overloading
    Cadena& operator=(const Cadena& c);
    Cadena& operator=(Cadena&& c);
    Cadena& operator=(const char*);
    explicit operator const char*() const noexcept;
    Cadena& operator+=(const Cadena& c);
    char& operator[](const size_t a);
    const char& operator[](const size_t a) const;

    // Accessors
    inline size_t length() const noexcept { return tam_; }
    const char& at(int i) const;
    char& at(int i);
    Cadena substr(int indice, int size) const;

    // Iterators
    typedef char* iterator;
    typedef const char* const_iterator;
    typedef std::reverse_iterator<iterator> reverse_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

    // Iterator Functions
    inline iterator begin() noexcept { return s_; }
    inline const_iterator begin() const noexcept { return const_iterator(s_); }
    inline iterator end() noexcept { return s_ + tam_; }
    inline const_iterator end() const noexcept { return const_iterator(s_ + tam_); }
    inline const_iterator cbegin() const noexcept { return const_iterator(s_); }
    inline const_iterator cend() const noexcept { return const_iterator(s_ + tam_); }
    inline reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
    inline const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
    inline reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
    inline const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
    inline const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
    inline const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }

    // Destructor
    ~Cadena();
};

// External Operator Overloads
Cadena operator+(const Cadena& c1, const Cadena& c2);
bool operator==(const Cadena& c1, const Cadena& c2);
bool operator!=(const Cadena& c1, const Cadena& c2);
bool operator<(const Cadena& c1, const Cadena& c2);
bool operator>(const Cadena& c1, const Cadena& c2);
bool operator<=(const Cadena& c1, const Cadena& c2);
bool operator>=(const Cadena& c1, const Cadena& c2);

std::ostream& operator<<(std::ostream& os, const Cadena& c) noexcept;
std::istream& operator>>(std::istream& is, Cadena& c);

#endif

cadena.cpp


#include "cadena.hpp"

char Cadena::vacia[1] = { '\0' };

// Constructors
Cadena::Cadena(int tam, char s) : tam_((size_t)tam) {
    if (tam < 0) throw std::length_error("tamaño negativo");
    if (tam_ == 0) {
        s_ = &vacia[0];
    } else {
        s_ = new char[tam_ + 1];
        for (size_t i = 0; i < tam_; i++) s_[i] = s;
        s_[tam_] = vacia[0];
    }
}

Cadena::Cadena(const char* c) : tam_(strlen(c)) {
    if (tam_ == 0) {
        s_ = &vacia[0];
    } else {
        s_ = new char[tam_ + 1];
        strcpy(s_, c);
        s_[tam_] = vacia[0];
    }
}

Cadena::Cadena(const Cadena& c) : tam_(c.tam_) {
    if (tam_ == 0) {
        s_ = &vacia[0];
    } else {
        s_ = new char[tam_ + 1];
        strcpy(s_, c.s_);
    }
}

Cadena::Cadena(Cadena&& c) : tam_(c.tam_), s_(c.s_) {
    c.tam_ = 0;
    c.s_ = &vacia[0];
}

// Operator Overloads
Cadena& Cadena::operator=(const Cadena& c) {
    if (*this != c) {
        if (0 != tam_) delete[] s_;
        tam_ = c.tam_;
        if (c.tam_ == 0) {
            s_ = &vacia[0];
        } else {
            s_ = new char[tam_ + 1];
            for (size_t i = 0; i <= tam_; i++) {
                s_[i] = c.s_[i];
            }
        }
    }
    return *this;
}

Cadena& Cadena::operator=(Cadena&& c) {
    if (this != &c) {
        if (0 != tam_) delete[] s_;
        tam_ = c.tam_;
        s_ = c.s_;
        c.tam_ = 0;
        c.s_ = &vacia[0];
    }
    return *this;
}

Cadena& Cadena::operator=(const char* c) {
    if (s_ != c) {
        if (0 < tam_) delete[] s_;
        tam_ = strlen(c);
        if (tam_ == 0) {
            s_ = &vacia[0];
        } else {
            s_ = new char[strlen(c) + 1];
            strcpy(s_, c);
        }
    }
    return *this;
}

Cadena::operator const char*() const noexcept { return s_; }

Cadena& Cadena::operator+=(const Cadena& c) { //dudo ,mejorable
    size_t tam = tam_ + c.tam_;
    char* aux = new char[tam + 1];

    for (size_t i = 0; i < tam_; i++) {
        aux[i] = s_[i];
    }
    for (size_t i = tam_, j = 0; i < tam; i++, j++) {
        aux[i] = c.s_[j];
    }
    aux[tam] = vacia[0];

    if (tam_ != 0) delete[] s_;
    tam_ = tam;
    s_ = new char[tam + 1];
    strcpy(s_, aux);
    delete[] aux;
    return *this;
}

char& Cadena::operator[](const size_t i) {
    return s_[i];
}

const char& Cadena::operator[](const size_t i) const {
    return s_[i];
}

// Accessors
char& Cadena::at(int i) {
    if (i < 0 || (int)tam_ <= i) throw std::out_of_range("Fuera del rango de la cadena");
    return s_[i];
}

const char& Cadena::at(int i) const {
    if (i < 0 || (int)tam_ <= i) throw std::out_of_range("Fuera del rango de la cadena");
    return s_[i];
}

Cadena Cadena::substr(int indice, int size) const {
    if (indice < 0 || size < 0) throw std::out_of_range("indice o tamaño negativos");
    if ((int)tam_ < indice) throw std::out_of_range("posicion inicial superior al tamaño");
    if ((int)tam_ < indice + size) throw std::out_of_range("indice + tamaño sale de rango");
    Cadena subs(size);
    for (int i = indice, j = 0; i < indice + size; i++, j++) {
        subs.s_[j] = s_[i];
    }
    return subs;
}

// Destructor
Cadena::~Cadena() {
    if (tam_ != 0) delete[] s_;
    tam_ = 0;
    s_ = nullptr;
}

// External Operator Overloads
Cadena operator+(const Cadena& c1, const Cadena& c2) {
    Cadena c(c1);
    c += c2;
    return c;
}

bool operator==(const Cadena& c1, const Cadena& c2) {
    return (strcmp((const char*)c1, (const char*)c2) == 0);
}

bool operator!=(const Cadena& c1, const Cadena& c2) {
    return !(c1 == c2);
}

bool operator<(const Cadena& c1, const Cadena& c2) {
    return (strcmp((const char*)c1, (const char*)c2) < 0);
}

bool operator>(const Cadena& c1, const Cadena& c2) {
    return c2 < c1;
}

bool operator<=(const Cadena& c1, const Cadena& c2) {
    return !(c2 < c1); // == !(c1 > c2)
}

bool operator>=(const Cadena& c1, const Cadena& c2) {
    return !(c1 < c2);
}

std::ostream& operator<<(std::ostream& os, const Cadena& c) noexcept {
    os << (const char*)c;
    return os;
}

std::istream& operator>>(std::istream& is, Cadena& cadena) {
    char cad[33] = "";
    is.width(33);
    is >> cad;
    cadena = cad;
    return is;
}