Program Listing for File CowString.hpp

Return to documentation for file (src/rdf4cpp/CowString.hpp)

#ifndef RDF4CPP_UTIL_COWSTRING_HPP
#define RDF4CPP_UTIL_COWSTRING_HPP

#include <string>
#include <string_view>
#include <variant>

namespace rdf4cpp {

struct CowString {
    using value_type = std::string_view::value_type;
    using traits_type = std::string_view::traits_type;
    using iterator = std::string_view::iterator;
    using const_iterator = std::string_view::const_iterator;
    using const_reverse_iterator = std::string_view::const_reverse_iterator;
    using reverse_iterator = std::string_view::reverse_iterator;
    using size_type = std::string_view::size_type;

    struct owned_tag {};
    struct borrowed_tag {};

    static constexpr owned_tag owned{};
    static constexpr borrowed_tag borrowed{};

private:
    using repr_t = std::variant<std::string, std::string_view>;
    repr_t data_;

public:
    constexpr CowString(borrowed_tag, std::string_view const value) noexcept : data_{std::in_place_type<std::string_view>, value} {}

    CowString(owned_tag, std::string const &value) : data_{std::in_place_type<std::string>, value} {}
    CowString(owned_tag, std::string &&value) noexcept : data_{std::in_place_type<std::string>, std::move(value)} {}

    [[nodiscard]] constexpr size_type size() const noexcept {
        return this->view().size();
    }

    [[nodiscard]] constexpr value_type const *data() const noexcept {
        return this->view().data();
    }

    [[nodiscard]] constexpr bool empty() const noexcept {
        return this->view().empty();
    }

    [[nodiscard]] constexpr const_iterator begin() const noexcept {
        return this->view().begin();
    }

    [[nodiscard]] constexpr const_iterator end() const noexcept {
        return this->view().end();
    }

    [[nodiscard]] constexpr const_iterator cbegin() const noexcept {
        return this->begin();
    }

    [[nodiscard]] constexpr const_iterator cend() const noexcept  {
        return this->end();
    }

    [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept {
        return this->view().rbegin();
    }

    [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept {
        return this->view().rend();
    }

    [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept {
        return this->rbegin();
    }

    [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept  {
        return this->rend();
    }

    constexpr operator std::string_view() const noexcept {
        return this->view();
    }

    [[nodiscard]] constexpr std::string_view view() const noexcept {
        return std::visit([](auto const &value) noexcept -> std::string_view {
            return value;
        }, this->data_);
    }

    [[nodiscard]] constexpr bool is_borrowed() const noexcept {
        return this->data_.index() == 1;
    }

    [[nodiscard]] constexpr bool is_owned() const noexcept {
        return this->data_.index() == 0;
    }

    [[nodiscard]] constexpr std::string_view get_borrowed() const {
        return std::get<std::string_view>(this->data_);
    }

    [[nodiscard]] constexpr std::string const &get_owned() const {
        return std::get<std::string>(this->data_);
    }

    [[nodiscard]] constexpr std::string &get_owned() {
        return std::get<std::string>(this->data_);
    }

    [[nodiscard]] std::string into_owned() const & noexcept {
        if (this->is_borrowed()) {
            return std::string{this->get_borrowed()};
        }

        return this->get_owned();
    }

    [[nodiscard]] std::string into_owned() && noexcept {
        if (this->is_borrowed()) {
            return std::string{this->get_borrowed()};
        }

        return std::move(this->get_owned());
    }

    [[nodiscard]] std::string &to_mutable() noexcept {
        if (this->is_borrowed()) {
            this->data_ = std::string{this->get_borrowed()};
        }

        return this->get_owned();
    }

    constexpr std::strong_ordering operator<=>(CowString const &other) const noexcept {
        return this->view() <=> other.view();
    }

    constexpr bool operator==(CowString const &other) const noexcept {
        return this->view() == other.view();
    }

    constexpr std::strong_ordering operator<=>(std::string_view const rhs) const noexcept {
        return this->view() <=> rhs;
    }

    constexpr bool operator==(std::string_view const rhs) const noexcept {
        return this->view() == rhs;
    }

    friend std::ostream &operator<<(std::ostream &os, CowString const &cow) {
        os << cow.view();
        return os;
    }
};

} // namespace rdf4cpp

#endif  //RDF4CPP_UTIL_COWSTRING_HPP