Arbutils/src/String/StringView.hpp

133 lines
5.6 KiB
C++

#ifndef ARBUTILS_STRINGVIEW_HPP
#define ARBUTILS_STRINGVIEW_HPP
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string_view>
#include "BasicStringView.hpp"
#if WINDOWS
#define STDSTRINGCONSTEXPR
#else
#define STDSTRINGCONSTEXPR constexpr
#endif
namespace ArbUt {
class __ConstStringCharHolder {
char* _value = 0;
__ConstStringCharHolder(const __ConstStringCharHolder& o) = delete;
__ConstStringCharHolder& operator=(const __ConstStringCharHolder& other) = delete;
public:
__ConstStringCharHolder(const char* value, size_t length) noexcept : _value(new char[length + 1]) {
strncpy(_value, value, length + 1);
}
~__ConstStringCharHolder() noexcept { delete[] _value; }
inline constexpr const char* GetValue() const noexcept { return _value; }
};
}
inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; }
static uint32_t constexpr Hash(char const* input) {
return charToLower(*input) ? static_cast<uint32_t>(charToLower(*input)) + 33 * Hash(input + 1) : 5381;
};
static int constexpr CalcLength(const char* str) { return *str ? 1 + CalcLength(str + 1) : 0; }
namespace ArbUt {
/// \ingroup Strings
/// @brief A constant, non-editable string that allows copies to share the same string object.
class StringView final : public BasicStringView {
private:
static std::shared_ptr<__ConstStringCharHolder> __emptyString;
static inline const std::shared_ptr<__ConstStringCharHolder>& GetEmptyString() { return __emptyString; }
std::shared_ptr<__ConstStringCharHolder> _str = GetEmptyString();
public:
/// @brief Instantiate a StringView using a C string.
/// @param str A null-terminated C string.
StringView(const char* str) noexcept
: BasicStringView(CalcLength(str), Hash(str)), _str(new __ConstStringCharHolder(str, CalcLength(str))) {}
/// @brief Instantiate a StringView using a C string, as well as it's length.
/// @param str A null-terminated C string.
/// @param length The length of the C string
StringView(const char* str, size_t length) noexcept
: BasicStringView(length, Hash(str)), _str(new __ConstStringCharHolder(str, length)) {}
StringView() noexcept : BasicStringView(0, Hash("")) {}
/* Copy operators */
/// @brief Copy operator
/// @param other Other StringView
StringView(const StringView& other) noexcept : BasicStringView(other._length, other._hash), _str(other._str) {}
/// @brief Special constructor of stringview, specifically designed for use of conversion from StringViewLiteral
/// to StringView.
/// @param other Other StringView
/// @param c A null-terminated C string.
/// @param length The length of the C string.
StringView(const BasicStringView& other, const char* c, size_t length) noexcept
: BasicStringView(length, other.GetHash()), _str(new __ConstStringCharHolder(c, length)) {}
/// @brief Assignment operator.
/// @param other Stringview to assign.
/// @return current stringview.
StringView& operator=(const StringView& other) noexcept {
if (this == &other || _str == other._str) {
return *this;
}
_str = other._str;
_length = other._length;
_hash = other._hash;
return *this;
}
/// @brief Returns null-terminated C string.
/// @return Null-terminated C string.
[[nodiscard]] inline const char* c_str() const noexcept override { return _str->GetValue(); }
/// @brief Returns std string_view of internal C string.
/// @return std::string_view.
[[nodiscard]] inline std::string_view std_str() const noexcept override { return _str->GetValue(); }
inline constexpr bool operator==(const std::string_view& rhs) const noexcept override {
return _hash == Hash(rhs.data());
}
inline constexpr bool operator!=(const std::string_view& rhs) const noexcept override {
return _hash != Hash(rhs.data());
}
inline constexpr bool operator==(const char* rhs) const noexcept override { return _hash == Hash(rhs); }
inline constexpr bool operator!=(const char* rhs) const noexcept override { return _hash != Hash(rhs); }
/// @brief Calculates the hash for a given C string.
/// @param val A null-terminated C string.
/// @return A hash of the given string.
[[maybe_unused]] [[nodiscard]] inline static constexpr uint32_t CalculateHash(const char* val) noexcept {
return Hash(val);
}
/// @brief Calculates the hash for a given std string.
/// @param val A std string.
/// @return A hash of the given string.
[[maybe_unused]] [[nodiscard]] inline static constexpr uint32_t
CalculateHash(const std::string_view& val) noexcept {
return Hash(val.data());
}
/// @brief Returns an empty string.
/// @return An empty string.
static const StringView& EmptyString();
};
}
namespace std {
/// @brief Helper class for hashing string views.
template <> struct hash<ArbUt::StringView> {
/// @brief Returns the hash of a stringview.
/// @param s a StringView.
/// @return The hash of the StringView.
constexpr std::size_t operator()(ArbUt::StringView const& s) const noexcept { return s.GetHash(); }
};
}
#endif // ARBUTILS_STRINGVIEW_HPP