Skip to content

Commit

Permalink
Optimize FChar operations and processing
Browse files Browse the repository at this point in the history
  • Loading branch information
gansm committed Feb 14, 2024
1 parent 687d640 commit 2a52181
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 35 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
2023-02-14 Markus Gans <guru.mail@muenster.de>
* Optimize FChar operations and processing

2023-02-07 Markus Gans <guru.mail@muenster.de>
* Escape sequences can now be used to repeat UTF-8 characters, which
increases the display speed
Expand Down
115 changes: 96 additions & 19 deletions final/ftypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@

#define null nullptr

#ifdef __has_builtin
#define HAVE_BUILTIN(x) __has_builtin(x)
#else
#define HAVE_BUILTIN(x) 0
#endif

#define badAllocOutput(object_name) \
std::clog << FLog::LogLevel::Error \
<< __FILE__ << ":" << __LINE__ \
Expand Down Expand Up @@ -120,7 +126,7 @@ constexpr auto is7bit (CharT ch) noexcept -> bool
// Printable character verification
constexpr auto isPrintable (char ch) noexcept -> bool
{
return std::isprint(ch);
return std::isprint(int(ch));
}

constexpr auto isPrintable (wchar_t ch) noexcept -> bool
Expand Down Expand Up @@ -295,35 +301,71 @@ struct FCharAttribute
uInt8 : 8; // padding byte
};

#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr auto getFAttributeByte ( const FCharAttribute& fchar_attr
, std::size_t index ) noexcept -> uInt8
{
return (__builtin_bit_cast(uInt32, fchar_attr) >> (index << 3)) & 0xff;
}
#else
inline auto getFAttributeByte ( const FCharAttribute& fchar_attr
, std::size_t index ) noexcept -> uInt8
{
uInt8 byte{};
std::memcpy (&byte, reinterpret_cast<const uInt8*>(&fchar_attr) + index, sizeof(uInt8));
return byte;
}
#endif

#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr auto setFAttributeByte ( FCharAttribute& fchar_attr
, const std::size_t index
, const uInt8 value ) noexcept
{
if ( index >= sizeof(FCharAttribute) )
return; // index out of bounds

const auto clear_value = __builtin_bit_cast(uInt32, fchar_attr) & ~(uInt32(0xff) << (index << 3));
const auto ret = clear_value | (uInt32(value) << (index << 3));
fchar_attr = __builtin_bit_cast(FCharAttribute, ret);
}
#else
inline auto setFAttributeByte ( FCharAttribute& fchar_attr
, std::size_t index
, uInt8 value ) noexcept
{
assert ( index < sizeof(FCharAttribute) );
std::memcpy(reinterpret_cast<uInt8*>(&fchar_attr) + index, &value, sizeof(uInt8));
}
#endif

#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr auto getFAttributeWord (const FCharAttribute& fchar_attr) noexcept -> uInt32
{
return __builtin_bit_cast(uInt32, fchar_attr);
}
#else
inline auto getFAttributeWord (const FCharAttribute& fchar_attr) noexcept -> uInt32
{
uInt32 word{};
std::memcpy(&word, &fchar_attr, sizeof(word));
return word;
}
#endif

#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr auto WordToFAttribute (uInt32 word) noexcept -> FCharAttribute
{
return __builtin_bit_cast(FCharAttribute, word);
}
#else
inline auto WordToFAttribute (uInt32 word) noexcept -> FCharAttribute
{
FCharAttribute fchar_attr{};
std::memcpy(&fchar_attr, &word, sizeof(fchar_attr));
return fchar_attr;
}
#endif

union FAttribute
{
Expand All @@ -349,35 +391,70 @@ struct FChar

// FChar operator functions
//----------------------------------------------------------------------
#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr auto isFUnicodeEqual (const FUnicode& lhs, const FUnicode& rhs) noexcept -> bool
{
const auto* l_iter = std::cbegin(lhs);
const auto* r_iter = std::cbegin(rhs);
const auto* const l_last = std::cend(lhs);
// Check sizes first for early exit if sizes don't match
if ( lhs.size() != rhs.size() )
return false;

while ( *l_iter == *r_iter && *l_iter != L'\0' && l_iter != l_last )
{
++l_iter;
++r_iter;
}
// Perform a byte-wise comparison
return std::memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(wchar_t)) == 0;
}
#else
inline auto isFUnicodeEqual (const FUnicode& lhs, const FUnicode& rhs) noexcept -> bool
{
static_assert ( lhs.size() == rhs.size() , "Both sides are different sizes.");
// Perform a byte-wise comparison
return std::memcmp(lhs.data(), rhs.data(), lhs.size() * sizeof(wchar_t)) == 0;
}
#endif

return *l_iter == *r_iter;
//----------------------------------------------------------------------
#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr auto getCompareBitMask() noexcept -> uInt32
{
constexpr const FAttribute mask {{ 0xff, 0xff, 0x04, 0x00 }};
return __builtin_bit_cast(uInt32, mask.byte);
}
#else
inline auto getCompareBitMask() noexcept -> uInt32
{
const FAttribute mask {{ 0xff, 0xff, 0x04, 0x00 }};
uInt32 word{};
std::memcpy(&word, &mask, sizeof(word));
return word;
}
#endif

//----------------------------------------------------------------------
constexpr auto operator == (const FChar& lhs, const FChar& rhs) noexcept -> bool
#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr
#else
inline
#endif
auto operator == (const FChar& lhs, const FChar& rhs) noexcept -> bool
{
return isFUnicodeEqual(lhs.ch, rhs.ch)
&& lhs.fg_color == rhs.fg_color
&& lhs.bg_color == rhs.bg_color
&& lhs.attr.byte[0] == rhs.attr.byte[0]
&& lhs.attr.byte[1] == rhs.attr.byte[1]
&& lhs.attr.bit.fullwidth_padding \
== rhs.attr.bit.fullwidth_padding;
if ( ! isFUnicodeEqual(lhs.ch, rhs.ch)
|| lhs.fg_color != rhs.fg_color
|| lhs.bg_color != rhs.bg_color )
return false;

const auto mask = getCompareBitMask();

if ( (lhs.attr.word & mask) != (rhs.attr.word & mask) )
return false;

return true;
}

//----------------------------------------------------------------------
constexpr auto operator != (const FChar& lhs, const FChar& rhs) noexcept -> bool
#if HAVE_BUILTIN(__builtin_bit_cast)
constexpr
#else
inline
#endif
auto operator != (const FChar& lhs, const FChar& rhs) noexcept -> bool
{
return ! ( lhs == rhs );
}
Expand Down
8 changes: 4 additions & 4 deletions final/output/tty/ftermoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ auto FTermOutput::eraseCharacters (uInt& x, uInt xmax, uInt y) -> PrintState
if ( ! ec || print_char->ch[0] != L' ' )
return PrintState::NothingPrinted;

uInt whitespace = countRepetitions(print_char, x, xmax);
auto whitespace = countRepetitions(print_char, x, xmax);

if ( whitespace == 1 )
{
Expand Down Expand Up @@ -1008,7 +1008,7 @@ auto FTermOutput::repeatCharacter (uInt& x, uInt xmax, uInt y) -> PrintState
if ( ! rp && ! lr )
return PrintState::NothingPrinted;

uInt repetitions = countRepetitions(print_char, x, xmax);
auto repetitions = countRepetitions(print_char, x, xmax);

if ( repetitions == 1 )
{
Expand All @@ -1024,15 +1024,15 @@ auto FTermOutput::repeatCharacter (uInt& x, uInt xmax, uInt y) -> PrintState
const uInt end_pos = x + repetitions - 1;
const auto repetition_type = getRepetitionType(print_char, repetitions);

if ( repetition_type == Repetition::ASCII )
if ( rp && repetition_type == Repetition::ASCII )
{
newFontChanges (*print_char);
charsetChanges (*print_char);
appendAttributes (*print_char);
appendOutputBuffer (FTermControl{FTermcap::encodeParameter(rp, print_char->ch[0], repetitions)});
term_pos->x_ref() += static_cast<int>(repetitions);
}
else if ( repetition_type == Repetition::UTF8 )
else if ( lr && repetition_type == Repetition::UTF8 )
{
appendChar (*print_char);
appendOutputBuffer (FTermControl{FTermcap::encodeParameter(lr, repetitions)});
Expand Down
30 changes: 24 additions & 6 deletions final/vterm/fvterm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <numeric>
#include <string>
#include <unordered_set>
#include <vector>

#include "final/fapplication.h"
Expand Down Expand Up @@ -63,6 +64,27 @@ FVTerm::FTermArea* FVTerm::active_area{nullptr};
uInt8 FVTerm::b1_print_trans_mask{};
int FVTerm::tabstop{8};

using TransparentInvisibleLookupMap = std::unordered_set<wchar_t>;

//----------------------------------------------------------------------
static auto getTransparentInvisibleLookupMap() -> TransparentInvisibleLookupMap
{
// Encapsulate global unordered_map object
static const auto& trans_inv_lookup = std::make_unique<TransparentInvisibleLookupMap>
(
std::initializer_list<wchar_t>
({
wchar_t(UniChar::LowerHalfBlock),
wchar_t(UniChar::UpperHalfBlock),
wchar_t(UniChar::LeftHalfBlock),
wchar_t(UniChar::RightHalfBlock),
wchar_t(UniChar::MediumShade),
wchar_t(UniChar::FullBlock)
})
);

return *trans_inv_lookup;
}

//----------------------------------------------------------------------
// class FVTerm
Expand Down Expand Up @@ -1488,13 +1510,9 @@ inline auto FVTerm::isFCharTransparent (const FChar& fchar) const -> bool
//----------------------------------------------------------------------
inline auto FVTerm::isTransparentInvisible (const FChar& fchar) const -> bool
{
static const auto& trans_inv_chars = getTransparentInvisibleLookupMap();
const auto& fist_char = fchar.ch[0];
return ( fist_char == UniChar::LowerHalfBlock
|| fist_char == UniChar::UpperHalfBlock
|| fist_char == UniChar::LeftHalfBlock
|| fist_char == UniChar::RightHalfBlock
|| fist_char == UniChar::MediumShade
|| fist_char == UniChar::FullBlock );
return trans_inv_chars.find(fist_char) != trans_inv_chars.end();
}

//----------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions final/widget/ftextview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,8 @@ inline auto FTextView::isPrintable (wchar_t ch) const -> bool
// Check for printable characters

const bool utf8 = (FVTerm::getFOutput()->getEncoding() == Encoding::UTF8);
return ( (utf8 && isPrintable(ch))
|| (! utf8 && isPrintable(char(ch))) );
return ( (utf8 && finalcut::isPrintable(ch))
|| (! utf8 && finalcut::isPrintable(char(ch))) );
}

//----------------------------------------------------------------------
Expand Down
6 changes: 2 additions & 4 deletions test/foptiattr-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2018-2023 Markus Gans *
* Copyright 2018-2024 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
Expand Down Expand Up @@ -192,9 +192,7 @@ void FOptiAttrTest::sgrOptimizerTest()
to.attr.bit.dim = true;
to.attr.bit.italic = true;
CPPUNIT_ASSERT ( from != to );
//std::cerr << "--->"
// << printSequence(oa.changeAttribute(from, to))
// << "<---\n";

CPPUNIT_ASSERT_STRING ( oa.changeAttribute(from, to)
, CSI "0;10;2;1;3;34;47m" );
CPPUNIT_ASSERT ( from == to );
Expand Down

0 comments on commit 2a52181

Please sign in to comment.