omni/String.h
File members: omni/String.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 "../carb/Defines.h"
#include "detail/PointerIterator.h"
#include "../carb/cpp/StringView.h"
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <istream>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <string>
#include <type_traits>
#if CARB_HAS_CPP17
# include <string_view>
#endif
#if CARB_HAS_CPP20
# include <version>
# if defined __cpp_lib_constexpr_string && __cpp_lib_constexpr_string >= 201907L
# define CARBLOCAL_STDSTRING_CONSTEXPR constexpr
# else
# define CARBLOCAL_STDSTRING_CONSTEXPR
# endif
# if defined __cpp_constexpr && __cpp_constexpr >= 202002L
# define CARBLOCAL_UNION_CONSTEXPR constexpr
# else
# define CARBLOCAL_UNION_CONSTEXPR
# endif
#else
# define CARBLOCAL_STDSTRING_CONSTEXPR
# define CARBLOCAL_UNION_CONSTEXPR
#endif
CARB_IGNOREWARNING_MSC_WITH_PUSH(4201) // nonstandard extension used: nameless struct/union.
namespace omni
{
struct formatted_t
{
};
constexpr formatted_t formatted{};
struct vformatted_t
{
};
constexpr vformatted_t vformatted{};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace detail
{
struct char_traits
{
static constexpr void assign(char& dest, const char& c) noexcept;
static constexpr char* assign(char* dest, std::size_t count, char c) noexcept;
static constexpr void move(char* dest, const char* source, std::size_t count) noexcept;
static constexpr void copy(char* dest, const char* source, std::size_t count) noexcept;
static constexpr int compare(const char* s1, const char* s2, std::size_t count) noexcept;
static constexpr std::size_t length(const char* s) noexcept;
static constexpr const char* find(const char* s, std::size_t count, char ch) noexcept;
};
# if CARB_HAS_CPP17
template <typename T, typename Res = void>
using is_sv_convertible =
std::enable_if_t<std::conjunction<std::is_convertible<const T&, std::string_view>,
std::negation<std::is_convertible<const T&, const char*>>>::value,
Res>;
# endif
} // namespace detail
#endif
// Handle case where Windows.h may have defined 'max'
#pragma push_macro("max")
#undef max
class CARB_VIZ string
{
public:
#if CARB_HAS_CPP20 && defined __cpp_lib_constexpr_string && __cpp_lib_constexpr_string >= 201907L
using traits_type = std::char_traits<char>;
#else
using traits_type = detail::char_traits;
#endif
using value_type = char;
using size_type = std::size_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using difference_type = std::pointer_traits<pointer>::difference_type;
using iterator = detail::PointerIterator<pointer, string>;
using const_iterator = detail::PointerIterator<const_pointer, string>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = std::reverse_iterator<iterator>;
static constexpr size_type npos = std::numeric_limits<size_type>::max();
string() noexcept;
string(size_type n, value_type c);
string(const string& str, size_type pos);
string(const string& str, size_type pos, size_type n);
string(const value_type* s, size_type n);
string(const value_type* s);
template <typename InputIterator>
string(InputIterator begin, InputIterator end);
string(const string& str);
string(string&& str) noexcept;
string(std::initializer_list<value_type> ilist);
template <class... Args>
string(formatted_t, const char* fmt, Args&&... args);
string(vformatted_t, const char* fmt, va_list ap);
explicit string(const std::string& str);
string(const std::string& str, size_type pos, size_type n);
explicit string(const carb::cpp::string_view& sv);
string(const carb::cpp::string_view& sv, size_type pos, size_type n);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
explicit string(const T& t);
template <typename T, typename = detail::is_sv_convertible<T>>
string(const T& t, size_type pos, size_type n);
#endif
string(std::nullptr_t) = delete;
~string() noexcept;
string& operator=(const string& str);
string& operator=(string&& str) noexcept;
string& operator=(const value_type* s);
string& operator=(value_type c);
string& operator=(std::initializer_list<value_type> ilist);
string& operator=(const std::string& str);
string& operator=(const carb::cpp::string_view& sv);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& operator=(const T& t);
#endif
string& operator=(std::nullptr_t) = delete;
string& assign(size_type n, value_type c);
string& assign(const string& str);
string& assign(const string& str, size_type pos, size_type n = npos);
string& assign(string&& str);
string& assign(const value_type* s, size_type n);
string& assign(const value_type* s);
template <class InputIterator>
string& assign(InputIterator first, InputIterator last);
string& assign(std::initializer_list<value_type> ilist);
string& assign(const std::string& str);
string& assign(const std::string& str, size_type pos, size_type n = npos);
string& assign(const carb::cpp::string_view& sv);
string& assign(const carb::cpp::string_view& sv, size_type pos, size_type n = npos);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& assign(const T& t);
template <typename T, typename = detail::is_sv_convertible<T>>
string& assign(const T& t, size_type pos, size_type n = npos);
#endif
string& assign_printf(const char* fmt, ...) CARB_PRINTF_FUNCTION(2, 3);
string& assign_vprintf(const char* fmt, va_list ap);
constexpr reference at(size_type pos);
constexpr const_reference at(size_type pos) const;
constexpr reference operator[](size_type pos);
constexpr const_reference operator[](size_type pos) const;
constexpr reference front();
constexpr const_reference front() const;
constexpr reference back();
constexpr const_reference back() const;
constexpr const value_type* data() const noexcept;
constexpr value_type* data() noexcept;
constexpr const value_type* c_str() const noexcept;
constexpr operator carb::cpp::string_view() const noexcept;
#if CARB_HAS_CPP17
constexpr operator std::string_view() const noexcept;
#endif
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cend() const noexcept;
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator crbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crend() const noexcept;
constexpr bool empty() const noexcept;
constexpr size_type size() const noexcept;
constexpr size_type length() const noexcept;
constexpr size_type max_size() const noexcept;
void reserve(size_type new_cap);
void reserve(); // deprecated in C++20
constexpr size_type capacity() const noexcept;
void shrink_to_fit();
constexpr void clear() noexcept;
string& insert(size_type pos, size_type n, value_type c);
string& insert(size_type pos, const value_type* s);
string& insert(size_type pos, const value_type* s, size_type n);
string& insert(size_type pos, const string& str);
string& insert(size_type pos1, const string& str, size_type pos2, size_type n = npos);
iterator insert(const_iterator p, value_type c);
iterator insert(const_iterator p, size_type n, value_type c);
template <class InputIterator>
iterator insert(const_iterator p, InputIterator first, InputIterator last);
iterator insert(const_iterator p, std::initializer_list<value_type> ilist);
string& insert(size_type pos, const std::string& str);
string& insert(size_type pos1, const std::string& str, size_type pos2, size_type n = npos);
string& insert(size_type pos, const carb::cpp::string_view& sv);
string& insert(size_type pos1, const carb::cpp::string_view& sv, size_type pos2, size_type n = npos);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& insert(size_type pos, const T& t);
template <typename T, typename = detail::is_sv_convertible<T>>
string& insert(size_type pos1, const T& t, size_type pos2, size_type n = npos);
#endif
string& insert_printf(size_type pos, const char* fmt, ...) CARB_PRINTF_FUNCTION(3, 4);
string& insert_vprintf(size_type pos, const char* fmt, va_list ap);
iterator insert_printf(const_iterator p, const char* fmt, ...) CARB_PRINTF_FUNCTION(3, 4);
iterator insert_vprintf(const_iterator p, const char* fmt, va_list ap);
constexpr string& erase(size_type pos = 0, size_type n = npos);
constexpr iterator erase(const_iterator pos);
constexpr iterator erase(const_iterator first, const_iterator last);
void push_back(value_type c);
constexpr void pop_back();
string& append(size_type n, value_type c);
string& append(const string& str);
string& append(const string& str, size_type pos, size_type n = npos);
string& append(const value_type* s, size_type n);
string& append(const value_type* s);
template <class InputIterator>
string& append(InputIterator first, InputIterator last);
string& append(std::initializer_list<value_type> ilist);
string& append(const std::string& str);
string& append(const std::string& str, size_type pos, size_type n = npos);
string& append(const carb::cpp::string_view& sv);
string& append(const carb::cpp::string_view& sv, size_type pos, size_type n = npos);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& append(const T& t);
template <typename T, typename = detail::is_sv_convertible<T>>
string& append(const T& t, size_type pos, size_type n = npos);
#endif
string& append_printf(const char* fmt, ...) CARB_PRINTF_FUNCTION(2, 3);
string& append_vprintf(const char* fmt, va_list ap);
string& operator+=(const string& str);
string& operator+=(value_type c);
string& operator+=(const value_type* s);
string& operator+=(std::initializer_list<value_type> ilist);
string& operator+=(const std::string& str);
string& operator+=(const carb::cpp::string_view& sv);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& operator+=(const T& t);
#endif
constexpr int compare(const string& str) const noexcept;
constexpr int compare(size_type pos1, size_type n1, const string& str) const;
constexpr int compare(size_type pos1, size_type n1, const string& str, size_type pos2, size_type n2 = npos) const;
constexpr int compare(const value_type* s) const;
constexpr int compare(size_type pos1, size_type n1, const value_type* s) const;
constexpr int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const;
CARBLOCAL_STDSTRING_CONSTEXPR int compare(const std::string& str) const noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR int compare(size_type pos1, size_type n1, const std::string& str) const;
CARBLOCAL_STDSTRING_CONSTEXPR int compare(
size_type pos1, size_type n1, const std::string& str, size_type pos2, size_type n2 = npos) const;
constexpr int compare(const carb::cpp::string_view& sv) const noexcept;
constexpr int compare(size_type pos1, size_type n1, const carb::cpp::string_view& sv) const;
constexpr int compare(
size_type pos1, size_type n1, const carb::cpp::string_view& sv, size_type pos2, size_type n2 = npos) const;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr int compare(const T& t) const noexcept;
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr int compare(size_type pos1, size_type n1, const T& t) const;
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr int compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const;
#endif
constexpr bool starts_with(value_type c) const noexcept;
constexpr bool starts_with(const_pointer s) const;
constexpr bool starts_with(carb::cpp::string_view sv) const noexcept;
#if CARB_HAS_CPP17
constexpr bool starts_with(std::string_view sv) const noexcept;
#endif
constexpr bool ends_with(value_type c) const noexcept;
constexpr bool ends_with(const_pointer s) const;
constexpr bool ends_with(carb::cpp::string_view sv) const noexcept;
#if CARB_HAS_CPP17
constexpr bool ends_with(std::string_view sv) const noexcept;
#endif
constexpr bool contains(value_type c) const noexcept;
constexpr bool contains(const_pointer s) const;
constexpr bool contains(carb::cpp::string_view sv) const noexcept;
#if CARB_HAS_CPP17
constexpr bool contains(std::string_view sv) const noexcept;
#endif
string& replace(size_type pos1, size_type n1, const string& str);
string& replace(size_type pos1, size_type n1, const string& str, size_type pos2, size_type n2 = npos);
template <class InputIterator>
string& replace(const_iterator i1, const_iterator i2, InputIterator j1, InputIterator j2);
string& replace(size_type pos, size_type n1, const value_type* s, size_type n2);
string& replace(size_type pos, size_type n1, const value_type* s);
string& replace(size_type pos, size_type n1, size_type n2, value_type c);
string& replace(size_type pos1, size_type n1, const std::string& str);
string& replace(size_type pos1, size_type n1, const std::string& str, size_type pos2, size_type n2 = npos);
string& replace(size_type pos1, size_type n1, const carb::cpp::string_view& sv);
string& replace(size_type pos1, size_type n1, const carb::cpp::string_view& sv, size_type pos2, size_type n2 = npos);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& replace(size_type pos1, size_type n1, const T& t);
template <typename T, typename = detail::is_sv_convertible<T>>
string& replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2);
#endif
string& replace(const_iterator i1, const_iterator i2, const string& str);
string& replace(const_iterator i1, const_iterator i2, const value_type* s, size_type n);
string& replace(const_iterator i1, const_iterator i2, const value_type* s);
string& replace(const_iterator i1, const_iterator i2, size_type n, value_type c);
string& replace(const_iterator i1, const_iterator i2, std::initializer_list<value_type> ilist);
string& replace(const_iterator i1, const_iterator i2, const std::string& str);
string& replace(const_iterator i1, const_iterator i2, const carb::cpp::string_view& sv);
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
string& replace(const_iterator i1, const_iterator i2, const T& t);
#endif
string& replace_format(size_type pos, size_type n1, const value_type* fmt, ...) CARB_PRINTF_FUNCTION(4, 5);
string& replace_vformat(size_type pos, size_type n1, const value_type* fmt, va_list ap);
string& replace_format(const_iterator i1, const_iterator i2, const value_type* fmt, ...) CARB_PRINTF_FUNCTION(4, 5);
string& replace_vformat(const_iterator i1, const_iterator i2, const value_type* fmt, va_list ap);
string substr(size_type pos = 0, size_type n = npos) const;
constexpr size_type copy(value_type* s, size_type n, size_type pos = 0) const;
void resize(size_type n, value_type c);
void resize(size_type n);
void swap(string& str) noexcept;
constexpr size_type find(const string& str, size_type pos = 0) const noexcept;
constexpr size_type find(const value_type* s, size_type pos, size_type n) const;
constexpr size_type find(const value_type* s, size_type pos = 0) const;
CARBLOCAL_STDSTRING_CONSTEXPR size_type find(const std::string& str, size_type pos = 0) const noexcept;
constexpr size_type find(const carb::cpp::string_view& sv, size_type pos = 0) const noexcept;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr size_type find(const T& t, size_type pos = 0) const noexcept;
#endif
constexpr size_type find(value_type c, size_type pos = 0) const noexcept;
constexpr size_type rfind(const string& str, size_type pos = npos) const noexcept;
constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const;
constexpr size_type rfind(const value_type* s, size_type pos = npos) const;
constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR size_type rfind(const std::string& str, size_type pos = npos) const noexcept;
constexpr size_type rfind(const carb::cpp::string_view& sv, size_type pos = npos) const noexcept;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr size_type rfind(const T& t, size_type pos = npos) const noexcept;
#endif
constexpr size_type find_first_of(const string& str, size_type pos = 0) const noexcept;
constexpr size_type find_first_of(const value_type* s, size_type pos, size_type n) const;
constexpr size_type find_first_of(const value_type* s, size_type pos = 0) const;
constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR size_type find_first_of(const std::string& str, size_type pos = 0) const noexcept;
constexpr size_type find_first_of(const carb::cpp::string_view& sv, size_type pos = 0) const noexcept;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr size_type find_first_of(const T& t, size_type pos = 0) const noexcept;
#endif
constexpr size_type find_last_of(const string& str, size_type pos = npos) const noexcept;
constexpr size_type find_last_of(const value_type* s, size_type pos, size_type n) const;
constexpr size_type find_last_of(const value_type* s, size_type pos = npos) const;
constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR size_type find_last_of(const std::string& str, size_type pos = npos) const noexcept;
constexpr size_type find_last_of(const carb::cpp::string_view& sv, size_type pos = npos) const noexcept;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr size_type find_last_of(const T& t, size_type pos = npos) const noexcept;
#endif
constexpr size_type find_first_not_of(const string& str, size_type pos = 0) const noexcept;
constexpr size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const;
constexpr size_type find_first_not_of(const value_type* s, size_type pos = 0) const;
constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR size_type find_first_not_of(const std::string& str, size_type pos = 0) const noexcept;
constexpr size_type find_first_not_of(const carb::cpp::string_view& sv, size_type pos = 0) const noexcept;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const noexcept;
#endif
constexpr size_type find_last_not_of(const string& str, size_type pos = npos) const noexcept;
constexpr size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const;
constexpr size_type find_last_not_of(const value_type* s, size_type pos = npos) const;
constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR size_type find_last_not_of(const std::string& str, size_type pos = npos) const noexcept;
constexpr size_type find_last_not_of(const carb::cpp::string_view& sv, size_type pos = npos) const noexcept;
#if CARB_HAS_CPP17
template <typename T, typename = detail::is_sv_convertible<T>>
constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const noexcept;
#endif
private:
// Size of the character buffer for small string optimization
constexpr static size_type kSMALL_STRING_SIZE = 32;
// The last byte of the SSO buffer contains the remaining size in the buffer
constexpr static size_type kSMALL_SIZE_OFFSET = kSMALL_STRING_SIZE - 1;
// Sentinel value indicating that the string is using heap allocated storage
constexpr static value_type kSTRING_IS_ALLOCATED = std::numeric_limits<char>::max();
// Struct that holds the data for an allocated string. This could be an anonymous struct inside the union,
// however naming it outside the union allows for the static_asserts below for ABI safety.
struct allocated_data
{
CARB_VIZ pointer m_ptr;
CARB_VIZ size_type m_size;
CARB_VIZ size_type m_capacity;
};
union
{
CARB_VIZ allocated_data m_allocated_data;
CARB_VIZ value_type m_local_data[kSMALL_STRING_SIZE];
};
static_assert(kSMALL_STRING_SIZE == 32, "ABI-safety: Cannot change the small string optimization size");
static_assert(size_type(kSTRING_IS_ALLOCATED) >= kSMALL_STRING_SIZE,
"Invalid assumption: Sentinel Value must be greater than max small string size.");
static_assert(sizeof(allocated_data) == 24, "ABI-safety: Cannot change allocated data size");
static_assert(offsetof(allocated_data, m_ptr) == 0, "ABI-safety: Member offset cannot change");
static_assert(offsetof(allocated_data, m_size) == 8, "ABI-safety: Member offset cannot change");
static_assert(offsetof(allocated_data, m_capacity) == 16, "ABI-safety: Member offset cannot change");
static_assert(sizeof(allocated_data) < kSMALL_STRING_SIZE,
"Invalid assumption: sizeof(allocated_data) must be less than the small string size.");
// Helper functions
constexpr bool is_local() const;
CARBLOCAL_UNION_CONSTEXPR void set_local(size_type new_size) noexcept;
CARBLOCAL_UNION_CONSTEXPR void set_allocated() noexcept;
constexpr reference get_reference(size_type pos) noexcept;
constexpr const_reference get_reference(size_type pos) const noexcept;
constexpr pointer get_pointer(size_type pos) noexcept;
constexpr const_pointer get_pointer(size_type pos) const noexcept;
CARBLOCAL_UNION_CONSTEXPR void set_empty() noexcept;
constexpr void range_check(size_type pos, size_type size, const char* function) const;
// Checks that pos is within the range [begin(), end()]
constexpr void range_check(const_iterator pos, const char* function) const;
// Checks that first is within the range [begin(), end()], that last is within the range [begin(), end()], and that
// first <= last.
constexpr void range_check(const_iterator first, const_iterator last, const char* function) const;
// Checks if current+n > max_size(). If it is not, returns current+n.
constexpr size_type length_check(size_type current, size_type n, const char* function) const;
constexpr void set_size(size_type new_size) noexcept;
constexpr bool should_allocate(size_type n) const noexcept;
constexpr bool overlaps_this_string(const_pointer s) const noexcept;
void overlap_check(const_pointer s) const;
// Calls std::vsnprintf, but throws if it fails
size_type vsnprintf_check(char* buffer, size_type buffer_size, const char* format, va_list args);
template <class... Args>
size_type snprintf_check(char* buffer, size_type buffer_size, const char* format, Args&&... args);
pointer allocate_if_necessary(size_type size);
void initialize(const_pointer src, size_type size);
template <typename InputIterator>
void initialize(InputIterator begin, InputIterator end, size_type size);
void dispose();
pointer allocate_buffer(size_type old_capacity, size_type& new_capacity);
pointer grow_buffer_to(size_type new_capacity);
// Grows a buffer to new_size, fills it with the data from the three provided pointers, and swaps the new buffer
// for the old one. This is used in functions like insert and replace, which may need to fill the new buffer with
// characters from multiple locations.
void grow_buffer_and_fill(
size_type new_size, const_pointer p1, size_type s1, const_pointer p2, size_type s2, const_pointer p3, size_type s3);
template <class InputIterator>
void grow_buffer_and_append(size_type new_size, InputIterator first, InputIterator last);
// Internal implementations
string& assign_internal(const_pointer src, size_type new_size);
template <typename InputIterator>
string& assign_internal(InputIterator begin, InputIterator end, size_type new_size);
string& insert_internal(size_type pos, value_type c, size_type n);
string& insert_internal(size_type pos, const_pointer src, size_type n);
string& append_internal(const_pointer src, size_type n);
constexpr int compare_internal(const_pointer this_str,
const_pointer other_str,
size_type this_size,
size_type other_size) const noexcept;
void replace_setup(size_type pos, size_type replaced_size, size_type replacement_size);
};
static_assert(std::is_standard_layout<string>::value, "string must be standard layout"); // Not interop-safe because not
// trivially copyable
static_assert(sizeof(string) == 32, "ABI Safety: String must be 32 bytes");
string operator+(const string& lhs, const string& rhs);
string operator+(const string& lhs, const char* rhs);
string operator+(const string& lhs, char rhs);
string operator+(const string& lhs, const std::string& rhs);
string operator+(const char* lhs, const string& rhs);
string operator+(char lhs, const string& rhs);
string operator+(const std::string& lhs, const string& rhs);
string operator+(string&& lhs, string&& rhs);
string operator+(string&& lhs, const string& rhs);
string operator+(string&& lhs, const char* rhs);
string operator+(string&& lhs, char rhs);
string operator+(string&& lhs, const string& rhs);
string operator+(const string& lhs, string&& rhs);
string operator+(const char* lhs, string&& rhs);
string operator+(char lhs, string&& rhs);
string operator+(const std::string& lhs, string&& rhs);
constexpr bool operator==(const string& lhs, const string& rhs) noexcept;
constexpr bool operator==(const string& lhs, const char* rhs);
constexpr bool operator==(const char* lhs, const string& rhs);
CARBLOCAL_STDSTRING_CONSTEXPR bool operator==(const string& lhs, const std::string& rhs) noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR bool operator==(const std::string& lhs, const string& rhs) noexcept;
constexpr bool operator!=(const string& lhs, const string& rhs) noexcept;
constexpr bool operator!=(const string& lhs, const char* rhs);
constexpr bool operator!=(const char* lhs, const string& rhs);
CARBLOCAL_STDSTRING_CONSTEXPR bool operator!=(const string& lhs, const std::string& rhs) noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR bool operator!=(const std::string& lhs, const string& rhs) noexcept;
constexpr bool operator<(const string& lhs, const string& rhs) noexcept;
constexpr bool operator<(const string& lhs, const char* rhs);
constexpr bool operator<(const char* lhs, const string& rhs);
CARBLOCAL_STDSTRING_CONSTEXPR bool operator<(const string& lhs, const std::string& rhs) noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR bool operator<(const std::string& lhs, const string& rhs) noexcept;
constexpr bool operator<=(const string& lhs, const string& rhs) noexcept;
constexpr bool operator<=(const string& lhs, const char* rhs);
constexpr bool operator<=(const char* lhs, const string& rhs);
CARBLOCAL_STDSTRING_CONSTEXPR bool operator<=(const string& lhs, const std::string& rhs) noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR bool operator<=(const std::string& lhs, const string& rhs) noexcept;
constexpr bool operator>(const string& lhs, const string& rhs) noexcept;
constexpr bool operator>(const string& lhs, const char* rhs);
constexpr bool operator>(const char* lhs, const string& rhs);
CARBLOCAL_STDSTRING_CONSTEXPR bool operator>(const string& lhs, const std::string& rhs) noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR bool operator>(const std::string& lhs, const string& rhs) noexcept;
constexpr bool operator>=(const string& lhs, const string& rhs) noexcept;
constexpr bool operator>=(const string& lhs, const char* rhs);
constexpr bool operator>=(const char* lhs, const string& rhs);
CARBLOCAL_STDSTRING_CONSTEXPR bool operator>=(const string& lhs, const std::string& rhs) noexcept;
CARBLOCAL_STDSTRING_CONSTEXPR bool operator>=(const std::string& lhs, const string& rhs) noexcept;
void swap(string& lhs, string& rhs) noexcept;
template <typename U>
CARB_CPP20_CONSTEXPR string::size_type erase(string& str, const U& val);
template <typename Pred>
CARB_CPP20_CONSTEXPR string::size_type erase_if(string& str, Pred pred);
std::basic_ostream<char, std::char_traits<char>>& operator<<(std::basic_ostream<char, std::char_traits<char>>& os,
const string& str);
std::basic_istream<char, std::char_traits<char>>& operator>>(std::basic_istream<char, std::char_traits<char>>& is,
string& str);
std::basic_istream<char, std::char_traits<char>>& getline(std::basic_istream<char, std::char_traits<char>>&& input,
string& str,
char delim);
std::basic_istream<char, std::char_traits<char>>& getline(std::basic_istream<char, std::char_traits<char>>&& input,
string& str);
int stoi(const string& str, std::size_t* pos = nullptr, int base = 10);
long stol(const string& str, std::size_t* pos = nullptr, int base = 10);
long long stoll(const string& str, std::size_t* pos = nullptr, int base = 10);
unsigned long stoul(const string& str, std::size_t* pos = nullptr, int base = 10);
unsigned long long stoull(const string& str, std::size_t* pos = nullptr, int base = 10);
float stof(const string& str, std::size_t* pos = nullptr);
double stod(const string& str, std::size_t* pos = nullptr);
long double stold(const string& str, std::size_t* pos = nullptr);
string to_string(int value);
string to_string(long value);
string to_string(long long value);
string to_string(unsigned value);
string to_string(unsigned long value);
string to_string(unsigned long long value);
string to_string(float value);
string to_string(double value);
string to_string(long double value);
} // namespace omni
namespace std
{
template <>
struct hash<omni::string>
{
using argument_type = omni::string;
using result_type = std::size_t;
size_t operator()(const argument_type& x) const noexcept
{
return carb::hashBuffer(x.data(), x.size());
}
};
} // namespace std
#include "String.inl"
#pragma pop_macro("max")
CARB_IGNOREWARNING_MSC_POP
#undef CARBLOCAL_STDSTRING_CONSTEXPR
#undef CARBLOCAL_UNION_CONSTEXPR