/************************************************************************************************** * This file is a part of Ultralight. * * * * See for licensing and more. * * * * (C) 2024 Ultralight, Inc. * **************************************************************************************************/ /// /// @file StringSTL.h /// /// STL compatibility header for ultralight::String. /// /// `#include ` /// /// This optional header provides utility functions for converting between ultralight::String, /// std::string, and std::string_view. It also provides support for using ultralight::String /// with standard library containers and stream operators. /// /// @pre This header requires C++17 or later. /// /// ## Example /// /// ```cpp /// #include /// #include /// #include /// /// ultralight::String myStr("Hello, world!"); /// /// // Convert ultralight::String to std::string /// std::string stdStr = ultralight::Convert(myStr); /// /// // Convert std::string to ultralight::String /// ultralight::String backToUl = ultralight::Convert(stdStr); /// /// // Print ultralight::String to std::cout /// std::cout << myStr << std::endl; /// ``` /// #pragma once #include #include #include #include namespace ultralight { /// /// Trait to check if a type is a supported string-like type. /// template struct is_string_type : std::false_type {}; template <> struct is_string_type : std::true_type {}; template <> struct is_string_type : std::true_type {}; template <> struct is_string_type : std::true_type {}; template <> struct is_string_type : std::true_type {}; /// /// Convert between string types. /// /// This function provides efficient conversion between different string types. /// It supports ultralight::String, std::string, std::string_view, and const char*. /// /// The following type conversions are automatically deduced (no template argument needed): /// - ultralight::String -> std::string /// - std::string -> ultralight::String /// - std::string_view -> ultralight::String /// - const char* -> ultralight::String /// /// For explicit conversion to std::string_view, use Convert(). /// /// @tparam To The target string type (optional, deduced in common cases) /// @tparam From The source string type (optional) /// /// @param from The string to convert /// /// @return The converted string in the target type /// /// ## Example /// /// ```cpp /// ultralight::String myStr("Hello, world!"); /// /// // ultralight::String -> std::string /// std::string stdStr = ultralight::Convert(myStr); /// /// // ultralight::String -> std::string_view /// std::string_view svStr = ultralight::Convert(myStr); /// /// // std::string -> ultralight::String /// ultralight::String backToUl = ultralight::Convert(stdStr); /// /// // std::string_view -> ultralight::String /// ultralight::String fromView = ultralight::Convert(std::string_view("View")); /// ``` /// template auto Convert(const From& from) { static_assert(is_string_type>>::value, "Convert only supports String, std::string, std::string_view, and const char*"); if constexpr (std::is_same_v) { // Automatic deduction if constexpr (std::is_same_v) { return std::string(from.utf8().data(), from.utf8().length()); } else if constexpr (std::is_same_v || std::is_same_v) { return String(from.data(), from.length()); } else if constexpr (std::is_same_v) { return String(from); // String constructor handles null-termination } else { // This case should never be reached due to the static_assert return From{}; } } else { // Explicit conversion static_assert(is_string_type::value, "Convert only supports String, std::string, std::string_view, and const char*"); if constexpr (std::is_same_v) { return from; } else if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { return String(from); // String constructor handles null-termination } else { return String(from.data(), from.length()); } } else if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { return std::string(from.utf8().data(), from.utf8().length()); } else if constexpr (std::is_same_v) { return std::string(from); // std::string constructor handles null-termination } else { return std::string(from); } } else if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { return std::string_view(from.utf8().data(), from.utf8().length()); } else if constexpr (std::is_same_v) { return std::string_view(from); // std::string_view constructor handles null-termination } else { return std::string_view(from); } } else if constexpr (std::is_same_v) { static_assert(!std::is_same_v, "Direct conversion to const char* is not supported due to ownership issues. " "Convert to String, std::string, or std::string_view instead."); } else { // This case should never be reached due to the static_assert return To{}; } } } } // namespace ultralight namespace std { /// /// Hash specialization for ultralight::String /// template<> struct hash { size_t operator()(const ultralight::String& str) const { return str.Hash(); } }; } // namespace std /// /// Stream output operator for ultralight::String. /// /// @param os The output stream. // /// @param str The string to output. /// /// @return The output stream. /// inline std::ostream& operator<<(std::ostream& os, const ultralight::String& str) { return os << ultralight::Convert(str); } /// /// Stream input operator for ultralight::String. /// /// @param is The input stream. /// /// @param str The string to input into. /// /// @return The input stream. /// inline std::istream& operator>>(std::istream& is, ultralight::String& str) { std::string temp; is >> temp; str = ultralight::Convert(temp); return is; }