Skip to content

Commit

Permalink
Add ICU library
Browse files Browse the repository at this point in the history
  • Loading branch information
a-n-t-h-o-n-y committed Jan 31, 2024
1 parent 3fdd578 commit 6f40fff
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 127 deletions.
20 changes: 6 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
20 changes: 9 additions & 11 deletions include/esc/detail/u32_to_mb.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
#ifndef ESC_DETAIL_U32_TO_MB_HPP
#define ESC_DETAIL_U32_TO_MB_HPP
#include <array>
#include <cstddef>
#include <utility>
#pragma once

#include <string>

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<std::size_t, std::array<char, 4>>;
/// 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
143 changes: 76 additions & 67 deletions include/esc/glyph.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#pragma once

#include <concepts>
#include <cstdint>
#include <ranges>
#include <string_view>
#include <vector>

#include <unicode/ucnv.h>
#include <unicode/unistr.h>

#include <esc/brush.hpp>
#include <esc/color.hpp>
Expand All @@ -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 <typename T>
concept Character = std::same_as<T, char> || std::same_as<T, signed char> ||
std::same_as<T, unsigned char> ||
std::same_as<T, wchar_t> || std::same_as<T, char8_t> ||
std::same_as<T, char16_t> || std::same_as<T, char32_t>;

/**
* @brief True if T is a valid Attribute type.
*/
/// True if T is a valid Attribute type.
template <typename T>
concept Attribute =
std::same_as<T, esc::ColorBG> || std::same_as<T, esc::ColorFG> ||
std::same_as<T, Trait> || std::same_as<T, esc::RemoveTrait>;

/**
* @brief True if T is a Forward iterable range of Glyphs.
*/
/// True if T is a Forward iterable range of Glyphs.
template <typename T>
concept GlyphString = std::ranges::forward_range<T> &&
std::same_as<std::ranges::range_value_t<T>, 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<char32_t>(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 <GlyphString T>
constexpr auto operator|(T&& gs, esc::ColorBG c) -> decltype(auto)
{
Expand All @@ -96,7 +82,7 @@ constexpr auto operator|(T&& gs, esc::ColorBG c) -> decltype(auto)
return std::forward<T>(gs);
}

// COLORFG ---------------------------------------------------------------------
// ------------------------------ COLORFG --------------------------------------

/**
* @brief Creates a Glyph with the given symbol and foreground Color.
Expand Down Expand Up @@ -141,7 +127,7 @@ constexpr auto operator|(T&& gs, esc::ColorFG c) -> decltype(auto)
return std::forward<T>(gs);
}

// TRAIT -----------------------------------------------------------------------
// ------------------------------- TRAIT ---------------------------------------

/**
* @brief Creates a Glyph with the given symbol and Trait.
Expand Down Expand Up @@ -181,7 +167,7 @@ constexpr auto operator|(T&& gs, Trait t) -> decltype(auto)
return std::forward<T>(gs);
}

// REMOVE TRAIT ----------------------------------------------------------------
// ---------------------------- REMOVE TRAIT -----------------------------------

/**
* @brief Removes a Trait from a Glyph's brush.
Expand Down Expand Up @@ -214,7 +200,7 @@ constexpr auto operator|(T&& gs, esc::RemoveTrait t) -> decltype(auto)
return std::forward<T>(gs);
}

// STRINGS ---------------------------------------------------------------------
// ------------------------------- STRINGS -------------------------------------

/**
* @brief Creates a std::vector<Glyph> from the given u32string_view and
Expand All @@ -228,7 +214,10 @@ template <Attribute T>
[[nodiscard]] constexpr auto operator|(std::u32string_view sv, T attr)
-> std::vector<Glyph>
{
auto glyphs = std::vector<Glyph>{std::begin(sv), std::end(sv)};
auto glyphs = std::vector<Glyph>{
std::begin(sv),
std::end(sv),
};
return glyphs | attr;
}

Expand All @@ -244,23 +233,21 @@ template <Attribute T>
[[nodiscard]] constexpr auto operator|(std::u16string_view sv, T attr)
-> std::vector<Glyph>
{
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<Glyph>{};
// 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<Glyph>{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<Glyph>{};
glyphs.reserve(u_str.length());

for (int32_t i = 0; i < u_str.length(); ++i) {
glyphs.push_back({
.symbol = static_cast<char32_t>(u_str.char32At(i)),
});
}

return glyphs | attr;
}

/**
Expand All @@ -276,10 +263,21 @@ template <Attribute T>
[[nodiscard]] constexpr auto operator|(std::u8string_view sv, T attr)
-> std::vector<Glyph>
{
return {};
// TODO - use ICU to convert to char32_t chars into the vector
// auto glyphs = std::vector<Glyph>{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<Glyph>{};
glyphs.reserve(u_str.length());

for (int32_t i = 0; i < u_str.length(); ++i) {
glyphs.push_back({
.symbol = static_cast<char32_t>(u_str.char32At(i)),
});
}

return glyphs | attr;
}

/**
Expand All @@ -295,10 +293,21 @@ template <Attribute T>
[[nodiscard]] constexpr auto operator|(std::string_view sv, T attr)
-> std::vector<Glyph>
{
return {};
// TODO - use ICU to convert to char32_t chars into the vector
// auto glyphs = std::vector<Glyph>{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<Glyph>{};
glyphs.reserve(u_str.length());

for (int32_t i = 0; i < u_str.length(); ++i) {
glyphs.push_back({
.symbol = static_cast<char32_t>(u_str.char32At(i)),
});
}

return glyphs | attr;
}

} // namespace esc
35 changes: 13 additions & 22 deletions src/detail/u32_to_mb.cpp
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
#include <esc/detail/u32_to_mb.hpp>

#include <array>
#include <cstddef>
#include <stdexcept>
#include <utility>
#include <string>

#ifdef __APPLE__
# include <cwchar>
#else
# include <cuchar>
#endif
#include <unicode/ucnv.h>
#include <unicode/unistr.h>
#include <unicode/utypes.h>

namespace esc::detail {

auto u32_to_mb(char32_t c) -> std::pair<std::size_t, std::array<char, 4>>
auto u32_to_mb(char32_t c) -> std::string
{
auto result = std::array<char, 4>{};
auto state = std::mbstate_t{};
auto status = U_ZERO_ERROR;
auto u_str = icu::UnicodeString(static_cast<UChar32>(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<wchar_t>(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
7 changes: 4 additions & 3 deletions src/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 6 additions & 10 deletions tests/glyph.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"}); }
}

0 comments on commit 6f40fff

Please sign in to comment.