CharTraits.h#
Fully qualified name: carb/cpp/detail/CharTraits.h
File members: carb/cpp/detail/CharTraits.h
// Copyright (c) 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 "../TypeTraits.h"
#include <string>
#if !CARB_HAS_CPP17
# include <functional>
#endif
namespace carb
{
namespace cpp
{
template <typename CharT>
struct char_traits : public std::char_traits<CharT>
{
using char_type = typename std::char_traits<CharT>::char_type;
using int_type = typename std::char_traits<CharT>::int_type;
using off_type = typename std::char_traits<CharT>::off_type;
using pos_type = typename std::char_traits<CharT>::pos_type;
using state_type = typename std::char_traits<CharT>::state_type;
#if CARB_HAS_CPP20
using comparison_category = typename std::char_traits<CharT>::comparison_category;
#endif
// For pre-C++20, define our own constexpr implementations
#if !(CARB_HAS_CPP20 && defined __cpp_lib_constexpr_string && __cpp_lib_constexpr_string >= 201907L) || \
defined DOXYGEN_BUILD
// Allow access to assign(char_type&, const char_type&)
using std::char_traits<CharT>::assign;
static constexpr char_type* assign(char_type* dest, std::size_t count, const char_type c) noexcept
{
for (char_type* temp = dest; count > 0; --count, ++temp)
*temp = c;
return dest;
}
static constexpr char_type* move(char_type* dest, const char_type* source, std::size_t count) noexcept
{
// Fallback basic constexpr implementation
if (dest == source)
{
// do nothing
}
else if (std::less<const char_type*>{}(source, dest))
{
// If source is less than dest, copy from the back to the front to avoid overwriting characters in source if
// source and dest overlap.
for (std::size_t i = count; i > 0; --i)
{
dest[i - 1] = source[i - 1];
}
}
else
{
// If source is greater than dest, copy from the the front to the back
for (std::size_t i = 0; i < count; ++i)
{
dest[i] = source[i];
}
}
return dest;
}
static constexpr char_type* copy(char_type* const dest, const char_type* const source, std::size_t const count) noexcept
{
// Fallback basic constexpr implementation
for (std::size_t i = 0; i < count; ++i)
{
dest[i] = source[i];
}
return dest;
}
#endif
#if !CARB_HAS_CPP17 || defined DOXYGEN_BUILD // For pre-C++17, define our own versions that are constexpr
static constexpr void assign(char_type& dest, const char_type& c) noexcept
{
dest = c;
}
[[nodiscard]] static constexpr int compare(const char_type* s1, const char_type* s2, std::size_t count) noexcept
{
for (; count > 0; --count, ++s1, ++s2)
if (*s1 != *s2)
return *s1 < *s2 ? -1 : +1;
return 0;
}
static constexpr const char_type* find(const char_type* s, std::size_t count, char_type const ch) noexcept
{
for (; count > 0; --count, ++s)
if (*s == ch)
return s;
return nullptr;
}
#endif
// vvv Carbonite extensions for security (we always override length())
template <size_t N>
[[nodiscard]] static constexpr std::size_t length(const char_type (&s)[N]) noexcept
{
return length_s(s, N);
}
#ifdef DOXYGEN_BUILD
[[nodiscard]] static constexpr std::size_t length(const char_type* s) noexcept;
#else
template <class T,
std::enable_if_t<!is_bounded_array_v<remove_cvref_t<T>> && std::is_convertible<T, const char_type*>::value,
bool> = false>
[[nodiscard]] static constexpr std::size_t length(T&& p) noexcept
#endif
{
#if CARB_HAS_CPP17
return std::char_traits<char_type>::length(p);
#else
const char_type* s = p;
std::size_t result = 0;
while (*s != char_type())
{
++result;
++s;
}
return result;
#endif
}
[[nodiscard]] static constexpr std::size_t length_s(const char_type* const s, std::size_t const max_count) noexcept
{
for (std::size_t i = 0; i != max_count; ++i)
{
if (!s[i])
{
return i;
}
}
return max_count;
}
template <std::size_t N>
[[nodiscard]] static constexpr std::size_t length_s(const char_type (&s)[N]) noexcept
{
return length_s(s, N);
}
};
} // namespace cpp
} // namespace carb