carb/RString.h
File members: carb/RString.h
// Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "Defines.h"
#define RSTRINGENUM_FROM_RSTRING_H
#include "RStringEnum.inl"
#undef RSTRINGENUM_FROM_RSTRING_H
#include <memory> // for std::owner_before
#include <ostream> // for std::basic_ostream
#include <stdint.h>
#include <string>
#include <typeindex> // for std::hash
namespace carb
{
enum class RStringOp
{
eRegister,
eFindExisting,
};
// conversion to 'unsigned int:31' from 'uint32_t {aka unsigned int}' may alter its value
CARB_IGNOREWARNING_GNUC_WITH_PUSH("-Wconversion")
namespace detail
{
struct RStringBase
{
CARB_VIZ uint32_t m_stringId : 31;
unsigned m_uncased : 1;
constexpr RStringBase(uint32_t stringId = 0, bool uncased = false) noexcept
: m_stringId(stringId), m_uncased(uncased)
{
}
};
// NOTE: In order to satisfy the StandardLayoutType named requirement (required for ABI safety), all non-static data
// members and bit-fields must be declared in the same class. As such, this class must match RStringBase, but cannot
// inherit from RStringBase.
struct RStringKeyBase
{
CARB_VIZ uint32_t m_stringId : 31;
unsigned m_uncased : 1;
CARB_VIZ int32_t m_number;
constexpr RStringKeyBase(uint32_t stringId = 0, bool uncased = false, int32_t number = 0) noexcept
: m_stringId(stringId), m_uncased(uncased), m_number(number)
{
}
};
CARB_IGNOREWARNING_GNUC_POP
// Validate assumptions
CARB_ASSERT_INTEROP_SAFE(RStringBase);
CARB_ASSERT_INTEROP_SAFE(RStringKeyBase);
static_assert(offsetof(RStringKeyBase, m_number) == sizeof(RStringBase), "Offset error");
template <bool Uncased, class Base = RStringBase>
class RStringTraits : protected Base
{
public:
static constexpr bool IsUncased = Uncased;
constexpr RStringTraits() noexcept;
constexpr RStringTraits(eRString staticString) noexcept;
RStringTraits(const char* str, RStringOp op);
RStringTraits(const char* str, size_t len, RStringOp op);
RStringTraits(const std::string& str, RStringOp op);
RStringTraits(uint32_t stringId) noexcept;
bool isValid() const noexcept;
constexpr bool isEmpty() const noexcept;
constexpr bool isUncased() const noexcept;
constexpr uint32_t getStringId() const noexcept;
size_t getHash() const;
size_t getUncasedHash() const noexcept;
const char* c_str() const noexcept;
const char* data() const noexcept;
size_t length() const noexcept;
#ifndef DOXYGEN_BUILD
std::string toString() const;
#endif
bool operator==(const RStringTraits& other) const;
bool operator!=(const RStringTraits& other) const;
bool owner_before(const RStringTraits& other) const;
template <bool OtherUncased, class OtherBase>
int compare(const RStringTraits<OtherUncased, OtherBase>& other) const;
int compare(const char* s) const;
int compare(size_t pos, size_t count, const char* s) const;
int compare(size_t pos, size_t count, const char* s, size_t len) const;
int compare(const std::string& s) const;
int compare(size_t pos, size_t count, const std::string& s) const;
};
} // namespace detail
class RString;
class RStringU;
class RStringKey;
class RStringUKey;
class CARB_VIZ RString final : public detail::RStringTraits<false>
{
using Base = detail::RStringTraits<false>;
public:
using Base::IsUncased;
constexpr RString() noexcept;
constexpr RString(eRString staticString) noexcept;
explicit RString(const char* str, RStringOp op = RStringOp::eRegister);
explicit RString(const char* str, size_t len, RStringOp op = RStringOp::eRegister);
explicit RString(const std::string& str, RStringOp op = RStringOp::eRegister);
explicit RString(const RStringKey& other) noexcept;
RStringU toUncased() const noexcept;
RString truncate() const noexcept;
RStringKey toRStringKey(int32_t number = 0) const;
bool operator==(const RString& other) const noexcept;
bool operator!=(const RString& other) const noexcept;
bool owner_before(const RString& other) const noexcept;
};
class CARB_VIZ RStringU final : public detail::RStringTraits<true>
{
using Base = detail::RStringTraits<true>;
public:
using Base::IsUncased;
constexpr RStringU() noexcept;
constexpr RStringU(eRString staticString) noexcept;
explicit RStringU(const char* str, RStringOp op = RStringOp::eRegister);
explicit RStringU(const char* str, size_t len, RStringOp op = RStringOp::eRegister);
explicit RStringU(const std::string& str, RStringOp op = RStringOp::eRegister);
explicit RStringU(const RString& other);
explicit RStringU(const RStringUKey& other);
RStringU toUncased() const noexcept;
RStringU truncate() const noexcept;
RStringUKey toRStringKey(int32_t number = 0) const;
bool operator==(const RStringU& other) const noexcept;
bool operator!=(const RStringU& other) const noexcept;
bool owner_before(const RStringU& other) const noexcept;
};
class CARB_VIZ RStringKey final : public detail::RStringTraits<false, detail::RStringKeyBase>
{
using Base = detail::RStringTraits<false, detail::RStringKeyBase>;
public:
using Base::IsUncased;
constexpr RStringKey() noexcept;
constexpr RStringKey(eRString staticString, int32_t number = 0) noexcept;
explicit RStringKey(const char* str, RStringOp op = RStringOp::eRegister);
RStringKey(int32_t number, const char* str, RStringOp op = RStringOp::eRegister);
explicit RStringKey(const char* str, size_t len, RStringOp op = RStringOp::eRegister);
explicit RStringKey(int32_t number, const char* str, size_t len, RStringOp op = RStringOp::eRegister);
explicit RStringKey(const std::string& str, RStringOp op = RStringOp::eRegister);
explicit RStringKey(int32_t number, const std::string& str, RStringOp op = RStringOp::eRegister);
RStringKey(const RString& str, int32_t number = 0);
RStringUKey toUncased() const noexcept;
RString truncate() const noexcept;
bool operator==(const RStringKey& other) const noexcept;
bool operator!=(const RStringKey& other) const noexcept;
bool owner_before(const RStringKey& other) const noexcept;
#ifndef DOXYGEN_BUILD // Sphinx warns about Duplicate C++ declaration
size_t getHash() const;
size_t getUncasedHash() const noexcept;
#endif
std::string toString() const;
int32_t getNumber() const noexcept;
void setNumber(int32_t num) noexcept;
int32_t& number() noexcept;
private:
// Hide these functions since they are incomplete
using Base::c_str;
using Base::data;
using Base::length;
};
class CARB_VIZ RStringUKey final : public detail::RStringTraits<true, detail::RStringKeyBase>
{
using Base = detail::RStringTraits<true, detail::RStringKeyBase>;
public:
using Base::IsUncased;
constexpr RStringUKey() noexcept;
constexpr RStringUKey(eRString staticString, int32_t number = 0) noexcept;
RStringUKey(const char* str, RStringOp op = RStringOp::eRegister);
RStringUKey(int32_t number, const char* str, RStringOp op = RStringOp::eRegister);
explicit RStringUKey(const char* str, size_t len, RStringOp op = RStringOp::eRegister);
explicit RStringUKey(int32_t number, const char* str, size_t len, RStringOp op = RStringOp::eRegister);
explicit RStringUKey(const std::string& str, RStringOp op = RStringOp::eRegister);
explicit RStringUKey(int32_t number, const std::string& str, RStringOp op = RStringOp::eRegister);
RStringUKey(const RStringU& str, int32_t number = 0);
explicit RStringUKey(const RStringKey& other);
RStringUKey toUncased() const noexcept;
RStringU truncate() const noexcept;
bool operator==(const RStringUKey& other) const noexcept;
bool operator!=(const RStringUKey& other) const noexcept;
bool owner_before(const RStringUKey& other) const noexcept;
#ifndef DOXYGEN_BUILD // Sphinx warns about Duplicate C++ declaration
size_t getHash() const;
size_t getUncasedHash() const noexcept;
#endif
std::string toString() const;
int32_t getNumber() const noexcept;
void setNumber(int32_t num) noexcept;
int32_t& number() noexcept;
private:
// Hide these functions since they are incomplete
using Base::c_str;
using Base::data;
using Base::length;
};
// Can use ADL specialization for global operator<< for stream output
template <class CharT, class Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& o, const RString& s)
{
o << s.c_str();
return o;
}
template <class CharT, class Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& o, const RStringU& s)
{
o << s.c_str();
return o;
}
template <class CharT, class Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& o, const RStringKey& s)
{
o << s.toString();
return o;
}
template <class CharT, class Traits>
::std::basic_ostream<CharT, Traits>& operator<<(::std::basic_ostream<CharT, Traits>& o, const RStringUKey& s)
{
o << s.toString();
return o;
}
} // namespace carb
// Specializations for std::hash and std::owner_less per type
template <>
struct std::hash<::carb::RString>
{
size_t operator()(const ::carb::RString& v) const
{
return v.getHash();
}
};
template <>
struct std::owner_less<::carb::RString>
{
bool operator()(const ::carb::RString& lhs, const ::carb::RString& rhs) const
{
return lhs.owner_before(rhs);
}
};
template <>
struct std::hash<::carb::RStringU>
{
size_t operator()(const ::carb::RStringU& v) const
{
return v.getHash();
}
};
template <>
struct std::owner_less<::carb::RStringU>
{
bool operator()(const ::carb::RStringU& lhs, const ::carb::RStringU& rhs) const
{
return lhs.owner_before(rhs);
}
};
template <>
struct std::hash<::carb::RStringKey>
{
size_t operator()(const ::carb::RStringKey& v) const
{
return v.getHash();
}
};
template <>
struct std::owner_less<::carb::RStringKey>
{
bool operator()(const ::carb::RStringKey& lhs, const ::carb::RStringKey& rhs) const
{
return lhs.owner_before(rhs);
}
};
template <>
struct std::hash<::carb::RStringUKey>
{
size_t operator()(const ::carb::RStringUKey& v) const
{
return v.getHash();
}
};
template <>
struct std::owner_less<::carb::RStringUKey>
{
bool operator()(const ::carb::RStringUKey& lhs, const ::carb::RStringUKey& rhs) const
{
return lhs.owner_before(rhs);
}
};
#include "RString.inl"