diff --git a/CMakeLists.txt b/CMakeLists.txt index 849b13a..c477b56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,12 @@ add_library(escape STATIC src/detail/signals.cpp ) +# UTF Support +find_package(ICU REQUIRED COMPONENTS dt uc i18n) +if(ICU_FOUND) + target_link_libraries(escape ICU::dt ICU::uc ICU::i18n) +endif() + target_include_directories(escape PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include @@ -39,20 +45,6 @@ target_compile_options(escape -Wpedantic ) -option(LTO "Turn Link Time Optimization ON/OFF" ON) - -# Link-Time Optimization -include(CheckIPOSupported) -check_ipo_supported(RESULT has_lto OUTPUT error) -if(has_lto AND LTO) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) - message("LTO Enabled Globally") -elseif(NOT has_lto) - message(WARNING "LTO is not supported: ${error}") -else() - message("LTO Not Enabled") -endif() - # TermCaps Executable add_executable(termcaps EXCLUDE_FROM_ALL tools/termcaps.cpp diff --git a/include/esc/detail/u32_to_mb.hpp b/include/esc/detail/u32_to_mb.hpp index 768a0aa..48fb81a 100644 --- a/include/esc/detail/u32_to_mb.hpp +++ b/include/esc/detail/u32_to_mb.hpp @@ -1,15 +1,13 @@ -#ifndef ESC_DETAIL_U32_TO_MB_HPP -#define ESC_DETAIL_U32_TO_MB_HPP -#include -#include -#include +#pragma once + +#include namespace esc::detail { -/// Convert the given char32_t into a multi-byte array of chars. -/** Depends on the currently set clocale to transform the char32_t. */ -[[nodiscard]] auto u32_to_mb(char32_t c) - -> std::pair>; +/// Convert the given char32_t into a multi-byte reprensentation as a string. +/// @param c The char32_t to convert. +/// @return The multi-byte representation of the given char32_t. +/// @throws std::runtime_error if the conversion fails. +[[nodiscard]] auto u32_to_mb(char32_t c) -> std::string; -} // namespace esc::detail -#endif // ESC_DETAIL_U32_TO_MB_HPP +} // namespace esc::detail \ No newline at end of file diff --git a/include/esc/glyph.hpp b/include/esc/glyph.hpp index 66797b0..2416e1b 100644 --- a/include/esc/glyph.hpp +++ b/include/esc/glyph.hpp @@ -1,8 +1,13 @@ #pragma once #include +#include #include #include +#include + +#include +#include #include #include @@ -21,72 +26,53 @@ struct Glyph { [[nodiscard]] constexpr bool operator!=(Glyph const&) const = default; }; -// CONCEPTS -------------------------------------------------------------------- +// ------------------------------ CONCEPTS ------------------------------------- -/** - * @brief True if T is a Character type. - */ +/// True if T is a Character type. template concept Character = std::same_as || std::same_as || std::same_as || std::same_as || std::same_as || std::same_as || std::same_as; -/** - * @brief True if T is a valid Attribute type. - */ +/// True if T is a valid Attribute type. template concept Attribute = std::same_as || std::same_as || std::same_as || std::same_as; -/** - * @brief True if T is a Forward iterable range of Glyphs. - */ +/// True if T is a Forward iterable range of Glyphs. template concept GlyphString = std::ranges::forward_range && std::same_as, Glyph>; -// ----------------------------- PIPE OPS -------------------------------------- -// COLORBG --------------------------------------------------------------------- - -// Note: For char literal based pipe ops, `using namespace ox` must be in scope. -// ADL issues prevent the pipe ops from being found otherwise. +// ------------------------------ PIPE OPS ------------------------------------- +// ------------------------------ COLORBG -------------------------------------- -/** - * @brief Creates a Glyph with the given symbol and background Color. - * - * @param symbol The symbol to display. - * @param c The ColorBG to apply to the return Glyph's brush. - * @return A Glyph with the given symbol and Color background. - */ +/// Creates a Glyph with the given symbol and background Color. +/// @param symbol The symbol to display. +/// @param c The ColorBG to apply to the return Glyph's brush. +/// @return A Glyph with the given symbol and Color background. [[nodiscard]] constexpr auto operator|(Character auto symbol, esc::ColorBG c) -> Glyph { return {static_cast(symbol), {.background = c.value}}; } -/** - * @brief Copy the Glyph and modify its background Color. - * - * @param g The Glyph to work from. - * @param c The ColorBG to apply to the return Glyph's brush. - * @return The passed in Glyph with the given Color background. - */ +/// Copy the Glyph and modify its background Color. +/// @param g The Glyph to work from. +/// @param c The ColorBG to apply to the return Glyph's brush. +/// @return The passed in Glyph with the given Color background. [[nodiscard]] constexpr auto operator|(Glyph g, esc::ColorBG c) -> Glyph { g.brush.background = c.value; return g; } -/** - * @brief Modify the Glyphs in the GlyphString to have the given background - * Color. - * - * @param gs The GlyphString to work from. - * @param c The ColorBG to apply to each Glyph's brush. - * @return The passed in GlyphString with the given Color background. - */ +/// Modify the Glyphs in the GlyphString to have the given background Color. +/// @param gs The GlyphString to work from. +/// @param c The ColorBG to apply to each Glyph's brush. +/// @return The passed in GlyphString with the given Color background. template constexpr auto operator|(T&& gs, esc::ColorBG c) -> decltype(auto) { @@ -96,7 +82,7 @@ constexpr auto operator|(T&& gs, esc::ColorBG c) -> decltype(auto) return std::forward(gs); } -// COLORFG --------------------------------------------------------------------- +// ------------------------------ COLORFG -------------------------------------- /** * @brief Creates a Glyph with the given symbol and foreground Color. @@ -141,7 +127,7 @@ constexpr auto operator|(T&& gs, esc::ColorFG c) -> decltype(auto) return std::forward(gs); } -// TRAIT ----------------------------------------------------------------------- +// ------------------------------- TRAIT --------------------------------------- /** * @brief Creates a Glyph with the given symbol and Trait. @@ -181,7 +167,7 @@ constexpr auto operator|(T&& gs, Trait t) -> decltype(auto) return std::forward(gs); } -// REMOVE TRAIT ---------------------------------------------------------------- +// ---------------------------- REMOVE TRAIT ----------------------------------- /** * @brief Removes a Trait from a Glyph's brush. @@ -214,7 +200,7 @@ constexpr auto operator|(T&& gs, esc::RemoveTrait t) -> decltype(auto) return std::forward(gs); } -// STRINGS --------------------------------------------------------------------- +// ------------------------------- STRINGS ------------------------------------- /** * @brief Creates a std::vector from the given u32string_view and @@ -228,7 +214,10 @@ template [[nodiscard]] constexpr auto operator|(std::u32string_view sv, T attr) -> std::vector { - auto glyphs = std::vector{std::begin(sv), std::end(sv)}; + auto glyphs = std::vector{ + std::begin(sv), + std::end(sv), + }; return glyphs | attr; } @@ -244,23 +233,21 @@ template [[nodiscard]] constexpr auto operator|(std::u16string_view sv, T attr) -> std::vector { - return {}; - // TODO from here - // implement this then uncomment line in test file. repeat. - // TODO review after library is installed - // auto uStr = icu::UnicodeString{icu::StringPiece{sv.data(), sv.size()}}; - - // auto glyphs = std::vector{}; - // glyphs.reserve(uStr.length()); - - // for (int32_t i = 0; i < uStr.length(); ++i) { - // glyphs.push_back(uStr.char32At(i)); - // } - - // return glyphs | attr; - // TODO - use ICU to convert to char32_t chars into the vector - // auto glyphs = std::vector{std::begin(sv), std::end(sv)}; - // return glyphs | attr; + auto const u_str = icu::UnicodeString{ + sv.data(), + (std::int32_t)sv.size(), + }; + + auto glyphs = std::vector{}; + glyphs.reserve(u_str.length()); + + for (int32_t i = 0; i < u_str.length(); ++i) { + glyphs.push_back({ + .symbol = static_cast(u_str.char32At(i)), + }); + } + + return glyphs | attr; } /** @@ -276,10 +263,21 @@ template [[nodiscard]] constexpr auto operator|(std::u8string_view sv, T attr) -> std::vector { - return {}; - // TODO - use ICU to convert to char32_t chars into the vector - // auto glyphs = std::vector{std::begin(sv), std::end(sv)}; - // return glyphs | attr; + auto const u_str = icu::UnicodeString::fromUTF8(icu::StringPiece{ + sv.data(), + (std::int32_t)sv.size(), + }); + + auto glyphs = std::vector{}; + glyphs.reserve(u_str.length()); + + for (int32_t i = 0; i < u_str.length(); ++i) { + glyphs.push_back({ + .symbol = static_cast(u_str.char32At(i)), + }); + } + + return glyphs | attr; } /** @@ -295,10 +293,21 @@ template [[nodiscard]] constexpr auto operator|(std::string_view sv, T attr) -> std::vector { - return {}; - // TODO - use ICU to convert to char32_t chars into the vector - // auto glyphs = std::vector{std::begin(sv), std::end(sv)}; - // return glyphs | attr; + auto const u_str = icu::UnicodeString::fromUTF8(icu::StringPiece{ + sv.data(), + (std::int32_t)sv.size(), + }); + + auto glyphs = std::vector{}; + glyphs.reserve(u_str.length()); + + for (int32_t i = 0; i < u_str.length(); ++i) { + glyphs.push_back({ + .symbol = static_cast(u_str.char32At(i)), + }); + } + + return glyphs | attr; } } // namespace esc \ No newline at end of file diff --git a/src/detail/u32_to_mb.cpp b/src/detail/u32_to_mb.cpp index 647831a..3ea2845 100644 --- a/src/detail/u32_to_mb.cpp +++ b/src/detail/u32_to_mb.cpp @@ -1,34 +1,25 @@ #include -#include -#include #include -#include +#include -#ifdef __APPLE__ -# include -#else -# include -#endif +#include +#include +#include namespace esc::detail { -auto u32_to_mb(char32_t c) -> std::pair> +auto u32_to_mb(char32_t c) -> std::string { - auto result = std::array{}; - auto state = std::mbstate_t{}; + auto status = U_ZERO_ERROR; + auto u_str = icu::UnicodeString(static_cast(c)); + auto result = std::string{}; + u_str.toUTF8String(result); -#ifdef __APPLE__ - static_assert(sizeof(wchar_t) == sizeof(char32_t)); - static_assert(alignof(wchar_t) == alignof(char32_t)); - auto const count = - std::wcrtomb(result.data(), static_cast(c), &state); -#else - auto const count = std::c32rtomb(result.data(), c, &state); -#endif - if (count == std::size_t(-1)) - throw std::runtime_error{"u32_to_mb(char32_t): Error in Conversion."}; - return {count, result}; + if (U_FAILURE(status)) { + throw std::runtime_error{"Unicode conversion failed"}; + } + return result; } } // namespace esc::detail diff --git a/src/io.cpp b/src/io.cpp index d004258..d608e52 100644 --- a/src/io.cpp +++ b/src/io.cpp @@ -830,9 +830,10 @@ void write(char c) { std::putchar(c); } void write(char32_t c) noexcept(false) { - auto const [count, chars] = esc::detail::u32_to_mb(c); - for (auto i = std::size_t{0}; i < count; ++i) - write(chars[i]); + write(esc::detail::u32_to_mb(c)); + // auto const [count, chars] = esc::detail::u32_to_mb(c); + // for (auto i = std::size_t{0}; i < count; ++i) + // write(chars[i]); } void write(std::string_view sv) diff --git a/tests/glyph.test.cpp b/tests/glyph.test.cpp index bac9de3..4de8e77 100644 --- a/tests/glyph.test.cpp +++ b/tests/glyph.test.cpp @@ -377,19 +377,15 @@ TEST_CASE("Operator|(StringType ...)", "[GlyphString]") SECTION("std::u32string") { test_string_pipe_ops(std::u32string{U"abc"}); } - // SECTION("char16_t const*") { test_string_pipe_ops(u"abc"); } + SECTION("char16_t const*") { test_string_pipe_ops(u"abc"); } - // SECTION("std::u16string") { test_string_pipe_ops(std::u16string{u"abc"}); - // } + SECTION("std::u16string") { test_string_pipe_ops(std::u16string{u"abc"}); } - // SECTION("char8_t const*") { test_string_pipe_ops(u8"abc"); } + SECTION("char8_t const*") { test_string_pipe_ops(u8"abc"); } - // SECTION("std::u8string") { test_string_pipe_ops(std::u8string{u8"abc"}); - // } + SECTION("std::u8string") { test_string_pipe_ops(std::u8string{u8"abc"}); } - // SECTION("wchar_t const*") { test_string_pipe_ops(L"abc"); } + SECTION("char const*") { test_string_pipe_ops("abc"); } - // SECTION("char const*") { test_string_pipe_ops("abc"); } - - // SECTION("std::string") { test_string_pipe_ops(std::string{"abc"}); } + SECTION("std::string") { test_string_pipe_ops(std::string{"abc"}); } }