Compare commits
1 commit
main
...
dev/lhecke
Author | SHA1 | Date | |
---|---|---|---|
6569666338 |
|
@ -17,8 +17,8 @@
|
|||
// Note: will through if unable to allocate char/attribute buffers
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build.
|
||||
CharRow::CharRow(size_t rowWidth, ROW* const pParent) noexcept :
|
||||
_data(rowWidth, value_type()),
|
||||
CharRow::CharRow(CharRowCell* buffer, size_t rowWidth, ROW* const pParent) noexcept :
|
||||
_data(buffer, rowWidth),
|
||||
_pParent{ FAIL_FAST_IF_NULL(pParent) }
|
||||
{
|
||||
}
|
||||
|
@ -53,38 +53,9 @@ void CharRow::Reset() noexcept
|
|||
// - resizes the width of the CharRowBase
|
||||
// Arguments:
|
||||
// - newSize - the new width of the character and attributes rows
|
||||
// Return Value:
|
||||
// - S_OK on success, otherwise relevant error code
|
||||
[[nodiscard]] HRESULT CharRow::Resize(const size_t newSize) noexcept
|
||||
void CharRow::Resize(CharRowCell* buffer, const size_t newSize) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
const value_type insertVals;
|
||||
_data.resize(newSize, insertVals);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
typename CharRow::iterator CharRow::begin() noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
typename CharRow::const_iterator CharRow::cbegin() const noexcept
|
||||
{
|
||||
return _data.cbegin();
|
||||
}
|
||||
|
||||
typename CharRow::iterator CharRow::end() noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
typename CharRow::const_iterator CharRow::cend() const noexcept
|
||||
{
|
||||
return _data.cend();
|
||||
_data = {buffer, newSize};
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -95,12 +66,16 @@ typename CharRow::const_iterator CharRow::cend() const noexcept
|
|||
// - The calculated left boundary of the internal string.
|
||||
size_t CharRow::MeasureLeft() const noexcept
|
||||
{
|
||||
const_iterator it = _data.cbegin();
|
||||
while (it != _data.cend() && it->IsSpace())
|
||||
const auto beg = _data.begin();
|
||||
const auto end = _data.end();
|
||||
|
||||
auto it = beg;
|
||||
while (it != end && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
return it - _data.cbegin();
|
||||
|
||||
return it - beg;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -111,17 +86,21 @@ size_t CharRow::MeasureLeft() const noexcept
|
|||
// - The calculated right boundary of the internal string.
|
||||
size_t CharRow::MeasureRight() const
|
||||
{
|
||||
const_reverse_iterator it = _data.crbegin();
|
||||
while (it != _data.crend() && it->IsSpace())
|
||||
const auto beg = _data.rbegin();
|
||||
const auto end = _data.rend();
|
||||
|
||||
auto it = beg;
|
||||
while (it != end && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
return _data.crend() - it;
|
||||
|
||||
return end - it;
|
||||
}
|
||||
|
||||
void CharRow::ClearCell(const size_t column)
|
||||
{
|
||||
_data.at(column).Reset();
|
||||
_data[column].Reset();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -132,7 +111,7 @@ void CharRow::ClearCell(const size_t column)
|
|||
// - True if there is valid text in this row. False otherwise.
|
||||
bool CharRow::ContainsText() const noexcept
|
||||
{
|
||||
for (const value_type& cell : _data)
|
||||
for (const auto& cell : _data)
|
||||
{
|
||||
if (!cell.IsSpace())
|
||||
{
|
||||
|
@ -151,7 +130,7 @@ bool CharRow::ContainsText() const noexcept
|
|||
// Note: will throw exception if column is out of bounds
|
||||
const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
|
||||
{
|
||||
return _data.at(column).DbcsAttr();
|
||||
return _data[column].DbcsAttr();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -163,7 +142,7 @@ const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
|
|||
// Note: will throw exception if column is out of bounds
|
||||
DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
|
||||
{
|
||||
return _data.at(column).DbcsAttr();
|
||||
return _data[column].DbcsAttr();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -175,7 +154,7 @@ DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
|
|||
// Note: will throw exception if column is out of bounds
|
||||
void CharRow::ClearGlyph(const size_t column)
|
||||
{
|
||||
_data.at(column).EraseChars();
|
||||
_data[column].EraseChars();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
|
|
@ -49,15 +49,12 @@ class CharRow final
|
|||
public:
|
||||
using glyph_type = typename wchar_t;
|
||||
using value_type = typename CharRowCell;
|
||||
using iterator = typename boost::container::small_vector_base<value_type>::iterator;
|
||||
using const_iterator = typename boost::container::small_vector_base<value_type>::const_iterator;
|
||||
using const_reverse_iterator = typename boost::container::small_vector_base<value_type>::const_reverse_iterator;
|
||||
using reference = typename CharRowCellReference;
|
||||
|
||||
CharRow(size_t rowWidth, ROW* const pParent) noexcept;
|
||||
CharRow(CharRowCell* buffer, size_t rowWidth, ROW* const pParent) noexcept;
|
||||
|
||||
size_t size() const noexcept;
|
||||
[[nodiscard]] HRESULT Resize(const size_t newSize) noexcept;
|
||||
void Resize(CharRowCell* buffer, const size_t newSize) noexcept;
|
||||
size_t MeasureLeft() const noexcept;
|
||||
size_t MeasureRight() const;
|
||||
bool ContainsText() const noexcept;
|
||||
|
@ -71,14 +68,25 @@ public:
|
|||
const reference GlyphAt(const size_t column) const;
|
||||
reference GlyphAt(const size_t column);
|
||||
|
||||
// iterators
|
||||
iterator begin() noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator begin() const noexcept { return cbegin(); }
|
||||
auto begin() noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
iterator end() noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
const_iterator end() const noexcept { return cend(); }
|
||||
auto begin() const noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
auto end() noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
auto end() const noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
UnicodeStorage& GetUnicodeStorage() noexcept;
|
||||
const UnicodeStorage& GetUnicodeStorage() const noexcept;
|
||||
|
@ -96,20 +104,21 @@ private:
|
|||
|
||||
protected:
|
||||
// storage for glyph data and dbcs attributes
|
||||
boost::container::small_vector<value_type, 120> _data;
|
||||
gsl::span<CharRowCell> _data;
|
||||
|
||||
// ROW that this CharRow belongs to
|
||||
ROW* _pParent;
|
||||
};
|
||||
|
||||
template<typename InputIt1, typename InputIt2>
|
||||
void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, CharRow::iterator outIt)
|
||||
template<typename InputIt1, typename InputIt2, typename OutputIt>
|
||||
void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, OutputIt outIt)
|
||||
{
|
||||
std::transform(startChars,
|
||||
endChars,
|
||||
startAttrs,
|
||||
outIt,
|
||||
[](const wchar_t wch, const DbcsAttribute attr) {
|
||||
return CharRow::value_type{ wch, attr };
|
||||
});
|
||||
std::transform(
|
||||
startChars,
|
||||
endChars,
|
||||
startAttrs,
|
||||
outIt,
|
||||
[](const wchar_t wch, const DbcsAttribute attr) {
|
||||
return CharRow::value_type{ wch, attr };
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ CharRowCellReference::operator std::wstring_view() const
|
|||
// - ref to the CharRowCell
|
||||
CharRowCell& CharRowCellReference::_cellData()
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -50,7 +50,7 @@ CharRowCell& CharRowCellReference::_cellData()
|
|||
// - ref to the CharRowCell
|
||||
const CharRowCell& CharRowCellReference::_cellData() const
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
// - pParent - the text buffer that this row belongs to
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) :
|
||||
ROW::ROW(const SHORT rowId, CharRowCell* buffer, const unsigned short rowWidth, const TextAttribute& fillAttribute, TextBuffer* const pParent) :
|
||||
_id{ rowId },
|
||||
_rowWidth{ rowWidth },
|
||||
_charRow{ rowWidth, this },
|
||||
_charRow{ buffer, rowWidth, this },
|
||||
_attrRow{ rowWidth, fillAttribute },
|
||||
_lineRendition{ LineRendition::SingleWidth },
|
||||
_wrapForced{ false },
|
||||
|
@ -34,7 +33,7 @@ ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute f
|
|||
// - Attr - The default attribute (color) to fill
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool ROW::Reset(const TextAttribute Attr)
|
||||
bool ROW::Reset(const TextAttribute& Attr)
|
||||
{
|
||||
_lineRendition = LineRendition::SingleWidth;
|
||||
_wrapForced = false;
|
||||
|
@ -52,26 +51,6 @@ bool ROW::Reset(const TextAttribute Attr)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - resizes ROW to new width
|
||||
// Arguments:
|
||||
// - width - the new width, in cells
|
||||
// Return Value:
|
||||
// - S_OK if successful, otherwise relevant error
|
||||
[[nodiscard]] HRESULT ROW::Resize(const unsigned short width)
|
||||
{
|
||||
RETURN_IF_FAILED(_charRow.Resize(width));
|
||||
try
|
||||
{
|
||||
_attrRow.Resize(width);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
_rowWidth = width;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - clears char data in column in row
|
||||
// Arguments:
|
||||
|
|
|
@ -32,9 +32,9 @@ class TextBuffer;
|
|||
class ROW final
|
||||
{
|
||||
public:
|
||||
ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent);
|
||||
ROW(const SHORT rowId, CharRowCell* buffer, const unsigned short rowWidth, const TextAttribute& fillAttribute, TextBuffer* const pParent);
|
||||
|
||||
size_t size() const noexcept { return _rowWidth; }
|
||||
size_t size() const noexcept { return _charRow.size(); }
|
||||
|
||||
void SetWrapForced(const bool wrap) noexcept { _wrapForced = wrap; }
|
||||
bool WasWrapForced() const noexcept { return _wrapForced; }
|
||||
|
@ -54,8 +54,7 @@ public:
|
|||
SHORT GetId() const noexcept { return _id; }
|
||||
void SetId(const SHORT id) noexcept { _id = id; }
|
||||
|
||||
bool Reset(const TextAttribute Attr);
|
||||
[[nodiscard]] HRESULT Resize(const unsigned short width);
|
||||
bool Reset(const TextAttribute& Attr);
|
||||
|
||||
void ClearColumn(const size_t column);
|
||||
std::wstring GetText() const { return _charRow.GetText(); }
|
||||
|
@ -74,13 +73,12 @@ private:
|
|||
CharRow _charRow;
|
||||
ATTR_ROW _attrRow;
|
||||
LineRendition _lineRendition;
|
||||
TextBuffer* _pParent; // non ownership pointer
|
||||
SHORT _id;
|
||||
unsigned short _rowWidth;
|
||||
// Occurs when the user runs out of text in a given row and we're forced to wrap the cursor to the next line
|
||||
bool _wrapForced;
|
||||
// Occurs when the user runs out of text to support a double byte character and we're forced to the next line
|
||||
bool _doubleBytePadded;
|
||||
TextBuffer* _pParent; // non ownership pointer
|
||||
};
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
|
|
|
@ -47,7 +47,7 @@ void UnicodeStorage::Erase(const key_type key) noexcept
|
|||
// - rowMap - A map of the old row IDs to the new row IDs.
|
||||
// - width - The width of the new row. Remove any items that are beyond the row width.
|
||||
// - Use nullopt if we're not resizing the width of the row, just renumbering the rows.
|
||||
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width)
|
||||
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, SHORT width)
|
||||
{
|
||||
// Make a temporary map to hold all the new row positioning
|
||||
std::unordered_map<key_type, mapped_type> newMap;
|
||||
|
@ -58,18 +58,10 @@ void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const
|
|||
// Extract the old coordinate position
|
||||
const auto oldCoord = pair.first;
|
||||
|
||||
// Only try to short-circuit based on width if we were told it changed
|
||||
// by being given a new width value.
|
||||
if (width.has_value())
|
||||
// If the column index is at/beyond the row width, don't bother copying it to the new map.
|
||||
if (oldCoord.X >= width)
|
||||
{
|
||||
// Get the column ID
|
||||
const auto oldColId = oldCoord.X;
|
||||
|
||||
// If the column index is at/beyond the row width, don't bother copying it to the new map.
|
||||
if (oldColId >= width.value())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the row ID from the position as that's what we need to remap
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
void Erase(const key_type key) noexcept;
|
||||
|
||||
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width);
|
||||
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, SHORT width);
|
||||
|
||||
private:
|
||||
std::unordered_map<key_type, mapped_type> _map;
|
||||
|
|
|
@ -31,26 +31,32 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
|
|||
const TextAttribute defaultAttributes,
|
||||
const UINT cursorSize,
|
||||
Microsoft::Console::Render::IRenderTarget& renderTarget) :
|
||||
_firstRow{ 0 },
|
||||
_currentAttributes{ defaultAttributes },
|
||||
_cursor{ cursorSize, *this },
|
||||
_storage{},
|
||||
_unicodeStorage{},
|
||||
_renderTarget{ renderTarget },
|
||||
_size{},
|
||||
_currentHyperlinkId{ 1 },
|
||||
_currentPatternId{ 0 }
|
||||
_renderTarget{ renderTarget }
|
||||
{
|
||||
// initialize ROWs
|
||||
const auto dx = static_cast<size_t>(screenBufferSize.X);
|
||||
const auto dy = static_cast<size_t>(screenBufferSize.Y);
|
||||
auto buffer = static_cast<CharRowCell*>(VirtualAlloc(nullptr, dx * dy * sizeof(CharRowCell), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
||||
THROW_IF_NULL_ALLOC(buffer);
|
||||
|
||||
_charBuffer = buffer;
|
||||
|
||||
_storage.reserve(static_cast<size_t>(screenBufferSize.Y));
|
||||
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
|
||||
for (SHORT i = 0; i < screenBufferSize.Y; ++i)
|
||||
{
|
||||
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this);
|
||||
_storage.emplace_back(i, buffer, screenBufferSize.X, _currentAttributes, this);
|
||||
buffer += dx;
|
||||
}
|
||||
|
||||
_UpdateSize();
|
||||
}
|
||||
|
||||
TextBuffer::~TextBuffer()
|
||||
{
|
||||
VirtualFree(_charBuffer, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Copies properties from another text buffer into this one.
|
||||
// - This is primarily to copy properties that would otherwise not be specified during CreateInstance
|
||||
|
@ -83,11 +89,9 @@ UINT TextBuffer::TotalRowCount() const noexcept
|
|||
// - const reference to the requested row. Asserts if out of bounds.
|
||||
const ROW& TextBuffer::GetRowByOffset(const size_t index) const
|
||||
{
|
||||
const size_t totalRows = TotalRowCount();
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
const size_t offsetIndex = (_firstRow + index) % _storage.size();
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -99,11 +103,9 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
|
|||
// - reference to the requested row. Asserts if out of bounds.
|
||||
ROW& TextBuffer::GetRowByOffset(const size_t index)
|
||||
{
|
||||
const size_t totalRows = TotalRowCount();
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
const size_t offsetIndex = (_firstRow + index) % _storage.size();
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
@ -400,7 +402,7 @@ OutputCellIterator TextBuffer::WriteLine(const OutputCellIterator givenIt,
|
|||
//Return Value:
|
||||
// - true if we successfully inserted the character
|
||||
// - false otherwise (out of memory)
|
||||
bool TextBuffer::InsertCharacter(const std::wstring_view chars,
|
||||
bool TextBuffer::InsertCharacter(const std::wstring_view& chars,
|
||||
const DbcsAttribute dbcsAttribute,
|
||||
const TextAttribute attr)
|
||||
{
|
||||
|
@ -778,7 +780,7 @@ void TextBuffer::ScrollRows(const SHORT firstRow, const SHORT size, const SHORT
|
|||
|
||||
// Renumber the IDs now that we've rearranged where the rows sit within the buffer.
|
||||
// Refreshing should also delegate to the UnicodeStorage to re-key all the stored unicode sequences (where applicable).
|
||||
_RefreshRowIDs(std::nullopt);
|
||||
_RefreshRowIDs(_size.Width());
|
||||
}
|
||||
|
||||
Cursor& TextBuffer::GetCursor() noexcept
|
||||
|
@ -896,6 +898,11 @@ void TextBuffer::Reset()
|
|||
{
|
||||
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
|
||||
|
||||
const auto dx = static_cast<size_t>(newSize.X);
|
||||
const auto dy = static_cast<size_t>(newSize.Y);
|
||||
auto buffer = static_cast<CharRowCell*>(VirtualAlloc(nullptr, dx * dy * sizeof(CharRowCell), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
||||
RETURN_IF_NULL_ALLOC(buffer);
|
||||
|
||||
try
|
||||
{
|
||||
const auto currentSize = GetSize().Dimensions();
|
||||
|
@ -909,12 +916,7 @@ void TextBuffer::Reset()
|
|||
const SHORT TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
|
||||
|
||||
// rotate rows until the top row is at index 0
|
||||
for (int i = 0; i < TopRowIndex; i++)
|
||||
{
|
||||
_storage.emplace_back(std::move(_storage.front()));
|
||||
_storage.erase(_storage.begin());
|
||||
}
|
||||
|
||||
std::rotate(_storage.begin(), _storage.begin() + TopRowIndex, _storage.end());
|
||||
_SetFirstRowIndex(0);
|
||||
|
||||
// realloc in the Y direction
|
||||
|
@ -926,19 +928,26 @@ void TextBuffer::Reset()
|
|||
// add rows if we're growing
|
||||
while (_storage.size() < static_cast<size_t>(newSize.Y))
|
||||
{
|
||||
_storage.emplace_back(static_cast<short>(_storage.size()), newSize.X, attributes, this);
|
||||
_storage.emplace_back(static_cast<short>(_storage.size()), nullptr, newSize.X, attributes, this);
|
||||
}
|
||||
|
||||
// Now that we've tampered with the row placement, refresh all the row IDs.
|
||||
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
|
||||
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
|
||||
_RefreshRowIDs(newSize.X);
|
||||
_RefreshRowWidth(buffer, newSize.X);
|
||||
|
||||
// Update the cached size value
|
||||
_UpdateSize();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
catch (...)
|
||||
{
|
||||
VirtualFree(buffer, 0, MEM_RELEASE);
|
||||
RETURN_CAUGHT_EXCEPTION();
|
||||
};
|
||||
|
||||
VirtualFree(_charBuffer, 0, MEM_RELEASE);
|
||||
_charBuffer = buffer;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -961,7 +970,7 @@ UnicodeStorage& TextBuffer::GetUnicodeStorage() noexcept
|
|||
// any high unicode (UnicodeStorage) runs while we're already looping through the rows.
|
||||
// Arguments:
|
||||
// - newRowWidth - Optional new value for the row width.
|
||||
void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
|
||||
void TextBuffer::_RefreshRowIDs(SHORT width)
|
||||
{
|
||||
std::unordered_map<SHORT, SHORT> rowMap;
|
||||
SHORT i = 0;
|
||||
|
@ -975,17 +984,19 @@ void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
|
|||
|
||||
// Also update the char row parent pointers as they can get shuffled up in the rotates.
|
||||
it.GetCharRow().UpdateParent(&it);
|
||||
|
||||
// Resize the rows in the X dimension if we have a new width
|
||||
if (newRowWidth.has_value())
|
||||
{
|
||||
// Realloc in the X direction
|
||||
THROW_IF_FAILED(it.Resize(newRowWidth.value()));
|
||||
}
|
||||
}
|
||||
|
||||
// Give the new mapping to Unicode Storage
|
||||
_unicodeStorage.Remap(rowMap, newRowWidth);
|
||||
_unicodeStorage.Remap(rowMap, width);
|
||||
}
|
||||
|
||||
void TextBuffer::_RefreshRowWidth(CharRowCell *data, size_t width) noexcept
|
||||
{
|
||||
for (auto& it : _storage)
|
||||
{
|
||||
it.GetCharRow().Resize(data, width);
|
||||
data += width;
|
||||
}
|
||||
}
|
||||
|
||||
void TextBuffer::_NotifyPaint(const Viewport& viewport) const
|
||||
|
@ -1044,7 +1055,7 @@ Microsoft::Console::Render::IRenderTarget& TextBuffer::GetRenderTarget() noexcep
|
|||
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
|
||||
// Return Value:
|
||||
// - the delimiter class for the given char
|
||||
const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const
|
||||
const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
return GetRowByOffset(pos.Y).GetCharRow().DelimiterClassAt(pos.X, wordDelimiters);
|
||||
}
|
||||
|
@ -1059,7 +1070,7 @@ const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std
|
|||
// (or a row boundary is encountered)
|
||||
// Return Value:
|
||||
// - The COORD for the first character on the "word" (inclusive)
|
||||
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const
|
||||
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode) const
|
||||
{
|
||||
// Consider a buffer with this text in it:
|
||||
// " word other "
|
||||
|
@ -1104,7 +1115,7 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
|
|||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The COORD for the first character on the current/previous READABLE "word" (inclusive)
|
||||
const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const
|
||||
const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
COORD result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
|
@ -1149,7 +1160,7 @@ const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const
|
|||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The COORD for the first character on the current word or delimiter run (stopped by the left margin)
|
||||
const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const
|
||||
const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
COORD result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
|
@ -1181,7 +1192,7 @@ const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std:
|
|||
// (or a row boundary is encountered)
|
||||
// Return Value:
|
||||
// - The COORD for the last character on the "word" (inclusive)
|
||||
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const
|
||||
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode) const
|
||||
{
|
||||
// Consider a buffer with this text in it:
|
||||
// " word other "
|
||||
|
@ -1218,7 +1229,7 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
|
|||
// - lastCharPos - the position of the last nonspace character in the text buffer (to improve performance)
|
||||
// Return Value:
|
||||
// - The COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer
|
||||
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const
|
||||
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view& wordDelimiters, const COORD lastCharPos) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
COORD result = target;
|
||||
|
@ -1266,7 +1277,7 @@ const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const st
|
|||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The COORD for the last character of the current word or delimiter run (stopped by right margin)
|
||||
const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const
|
||||
const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
|
@ -1349,7 +1360,7 @@ void TextBuffer::_PruneHyperlinks()
|
|||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The COORD for the first character on the "word" (inclusive)
|
||||
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const
|
||||
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view& wordDelimiters, COORD lastCharPos) const
|
||||
{
|
||||
// move to the beginning of the next word
|
||||
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
|
||||
|
@ -1373,7 +1384,7 @@ bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimite
|
|||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The COORD for the first character on the "word" (inclusive)
|
||||
bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters) const
|
||||
bool TextBuffer::MoveToPreviousWord(COORD& pos, const std::wstring_view& wordDelimiters) const
|
||||
{
|
||||
// move to the beginning of the current word
|
||||
auto copy{ GetWordStart(pos, wordDelimiters, true) };
|
||||
|
@ -1732,7 +1743,7 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
|
|||
// - string containing the generated HTML
|
||||
std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const std::wstring_view& fontFaceName,
|
||||
const COLORREF backgroundColor)
|
||||
{
|
||||
try
|
||||
|
@ -1795,7 +1806,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
|||
const auto writeAccumulatedChars = [&](bool includeCurrent) {
|
||||
if (col >= startOffset)
|
||||
{
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, rows.text.at(row).substr(startOffset, col - startOffset + includeCurrent));
|
||||
for (const auto c : unescapedText)
|
||||
{
|
||||
switch (c)
|
||||
|
@ -1921,7 +1932,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
|
|||
// - htmlTitle - value used in title tag of html header. Used to name the application
|
||||
// Return Value:
|
||||
// - string containing the generated RTF
|
||||
std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoints, const std::wstring_view fontFaceName, const COLORREF backgroundColor)
|
||||
std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoints, const std::wstring_view& fontFaceName, const COLORREF backgroundColor)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -1983,7 +1994,7 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
|
|||
const auto writeAccumulatedChars = [&](bool includeCurrent) {
|
||||
if (col >= startOffset)
|
||||
{
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
|
||||
const auto unescapedText = ConvertToA(CP_UTF8, rows.text.at(row).substr(startOffset, col - startOffset + includeCurrent));
|
||||
for (const auto c : unescapedText)
|
||||
{
|
||||
switch (c)
|
||||
|
@ -2361,9 +2372,9 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
|||
// - Adds or updates a hyperlink in our hyperlink table
|
||||
// Arguments:
|
||||
// - The hyperlink URI, the hyperlink id (could be new or old)
|
||||
void TextBuffer::AddHyperlinkToMap(std::wstring_view uri, uint16_t id)
|
||||
void TextBuffer::AddHyperlinkToMap(const std::wstring_view& uri, uint16_t id)
|
||||
{
|
||||
_hyperlinkMap[id] = uri;
|
||||
_hyperlinkMap.emplace(id, uri);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2383,28 +2394,31 @@ std::wstring TextBuffer::GetHyperlinkUriFromId(uint16_t id) const
|
|||
// - The user-defined id
|
||||
// Return value:
|
||||
// - The internal hyperlink ID
|
||||
uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id)
|
||||
uint16_t TextBuffer::GetHyperlinkId(const std::wstring_view& uri, const std::wstring_view& id)
|
||||
{
|
||||
uint16_t numericId = 0;
|
||||
if (id.empty())
|
||||
{
|
||||
// no custom id specified, return our internal count
|
||||
numericId = _currentHyperlinkId;
|
||||
++_currentHyperlinkId;
|
||||
numericId = _currentHyperlinkId++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// assign _currentHyperlinkId if the custom id does not already exist
|
||||
std::wstring newId{ id };
|
||||
// hash the URL and add it to the custom ID - GH#7698
|
||||
newId += L"%" + std::to_wstring(std::hash<std::wstring_view>{}(uri));
|
||||
const auto result = _hyperlinkCustomIdMap.emplace(newId, _currentHyperlinkId);
|
||||
// We need to use both uri and id for hashing. See GH#7698
|
||||
std::wstring key;
|
||||
key.reserve(uri.size() + id.size());
|
||||
key.append(uri);
|
||||
key.append(id);
|
||||
|
||||
const auto result = _hyperlinkCustomIdMap.emplace(key, _currentHyperlinkId);
|
||||
numericId = result.first->second;
|
||||
|
||||
if (result.second)
|
||||
{
|
||||
// the custom id did not already exist
|
||||
_hyperlinkCustomIdMapReverse.insert_or_assign(_currentHyperlinkId, key);
|
||||
++_currentHyperlinkId;
|
||||
}
|
||||
numericId = (*(result.first)).second;
|
||||
}
|
||||
// _currentHyperlinkId could overflow, make sure its not 0
|
||||
if (_currentHyperlinkId == 0)
|
||||
|
@ -2422,13 +2436,11 @@ uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id)
|
|||
void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
|
||||
{
|
||||
_hyperlinkMap.erase(id);
|
||||
for (const auto& customIdPair : _hyperlinkCustomIdMap)
|
||||
|
||||
if (auto it = _hyperlinkCustomIdMapReverse.find(id); it != _hyperlinkCustomIdMapReverse.end())
|
||||
{
|
||||
if (customIdPair.second == id)
|
||||
{
|
||||
_hyperlinkCustomIdMap.erase(customIdPair.first);
|
||||
break;
|
||||
}
|
||||
_hyperlinkCustomIdMap.erase(it->second);
|
||||
_hyperlinkCustomIdMapReverse.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2441,12 +2453,9 @@ void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
|
|||
// - The custom ID if there was one, empty string otherwise
|
||||
std::wstring TextBuffer::GetCustomIdFromId(uint16_t id) const
|
||||
{
|
||||
for (auto customIdPair : _hyperlinkCustomIdMap)
|
||||
if (auto it = _hyperlinkCustomIdMapReverse.find(id); it != _hyperlinkCustomIdMapReverse.end())
|
||||
{
|
||||
if (customIdPair.second == id)
|
||||
{
|
||||
return customIdPair.first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -2460,6 +2469,7 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
|
|||
{
|
||||
_hyperlinkMap = other._hyperlinkMap;
|
||||
_hyperlinkCustomIdMap = other._hyperlinkCustomIdMap;
|
||||
_hyperlinkCustomIdMapReverse = other._hyperlinkCustomIdMapReverse;
|
||||
_currentHyperlinkId = other._currentHyperlinkId;
|
||||
}
|
||||
|
||||
|
@ -2470,7 +2480,7 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
|
|||
// - The regex pattern
|
||||
// Return value:
|
||||
// - An ID that the caller should associate with the given pattern
|
||||
const size_t TextBuffer::AddPatternRecognizer(const std::wstring_view regexString)
|
||||
const size_t TextBuffer::AddPatternRecognizer(const std::wstring_view& regexString)
|
||||
{
|
||||
++_currentPatternId;
|
||||
_idsAndPatterns.emplace(std::make_pair(_currentPatternId, regexString));
|
||||
|
|
|
@ -69,6 +69,9 @@ public:
|
|||
const TextAttribute defaultAttributes,
|
||||
const UINT cursorSize,
|
||||
Microsoft::Console::Render::IRenderTarget& renderTarget);
|
||||
|
||||
~TextBuffer();
|
||||
|
||||
TextBuffer(const TextBuffer& a) = delete;
|
||||
|
||||
// Used for duplicating properties to another text buffer
|
||||
|
@ -98,7 +101,7 @@ public:
|
|||
const std::optional<size_t> limitRight = std::nullopt);
|
||||
|
||||
bool InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool InsertCharacter(const std::wstring_view chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool InsertCharacter(const std::wstring_view& chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
|
||||
bool IncrementCursor();
|
||||
bool NewlineCursor();
|
||||
|
||||
|
@ -141,10 +144,10 @@ public:
|
|||
|
||||
Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept;
|
||||
|
||||
const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const;
|
||||
const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const;
|
||||
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const;
|
||||
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const;
|
||||
const COORD GetWordStart(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode = false) const;
|
||||
const COORD GetWordEnd(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode = false) const;
|
||||
bool MoveToNextWord(COORD& pos, const std::wstring_view& wordDelimiters, COORD lastCharPos) const;
|
||||
bool MoveToPreviousWord(COORD& pos, const std::wstring_view& wordDelimiters) const;
|
||||
|
||||
const til::point GetGlyphStart(const til::point pos) const;
|
||||
const til::point GetGlyphEnd(const til::point pos) const;
|
||||
|
@ -153,9 +156,9 @@ public:
|
|||
|
||||
const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const;
|
||||
|
||||
void AddHyperlinkToMap(std::wstring_view uri, uint16_t id);
|
||||
void AddHyperlinkToMap(const std::wstring_view& uri, uint16_t id);
|
||||
std::wstring GetHyperlinkUriFromId(uint16_t id) const;
|
||||
uint16_t GetHyperlinkId(std::wstring_view uri, std::wstring_view id);
|
||||
uint16_t GetHyperlinkId(const std::wstring_view& uri, const std::wstring_view& id);
|
||||
void RemoveHyperlinkFromMap(uint16_t id) noexcept;
|
||||
std::wstring GetCustomIdFromId(uint16_t id) const;
|
||||
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
|
||||
|
@ -176,12 +179,12 @@ public:
|
|||
|
||||
static std::string GenHTML(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const std::wstring_view& fontFaceName,
|
||||
const COLORREF backgroundColor);
|
||||
|
||||
static std::string GenRTF(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const std::wstring_view& fontFaceName,
|
||||
const COLORREF backgroundColor);
|
||||
|
||||
struct PositionInformation
|
||||
|
@ -195,60 +198,47 @@ public:
|
|||
const std::optional<Microsoft::Console::Types::Viewport> lastCharacterViewport,
|
||||
std::optional<std::reference_wrapper<PositionInformation>> positionInfo);
|
||||
|
||||
const size_t AddPatternRecognizer(const std::wstring_view regexString);
|
||||
const size_t AddPatternRecognizer(const std::wstring_view& regexString);
|
||||
void ClearPatternRecognizers() noexcept;
|
||||
void CopyPatterns(const TextBuffer& OtherBuffer);
|
||||
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const size_t firstRow, const size_t lastRow) const;
|
||||
|
||||
private:
|
||||
void _UpdateSize();
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
std::vector<ROW> _storage;
|
||||
Cursor _cursor;
|
||||
|
||||
SHORT _firstRow; // indexes top row (not necessarily 0)
|
||||
|
||||
TextAttribute _currentAttributes;
|
||||
|
||||
// storage location for glyphs that can't fit into the buffer normally
|
||||
UnicodeStorage _unicodeStorage;
|
||||
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
uint16_t _currentHyperlinkId;
|
||||
|
||||
void _RefreshRowIDs(std::optional<SHORT> newRowWidth);
|
||||
|
||||
Microsoft::Console::Render::IRenderTarget& _renderTarget;
|
||||
|
||||
void _RefreshRowIDs(SHORT width);
|
||||
void _RefreshRowWidth(CharRowCell* data, size_t width) noexcept;
|
||||
void _SetFirstRowIndex(const SHORT FirstRowIndex) noexcept;
|
||||
|
||||
COORD _GetPreviousFromCursor() const;
|
||||
|
||||
void _SetWrapOnCurrentRow();
|
||||
void _AdjustWrapOnCurrentRow(const bool fSet);
|
||||
|
||||
void _NotifyPaint(const Microsoft::Console::Types::Viewport& viewport) const;
|
||||
|
||||
// Assist with maintaining proper buffer state for Double Byte character sequences
|
||||
bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
|
||||
ROW& _GetFirstRow();
|
||||
ROW& _GetPrevRowNoWrap(const ROW& row);
|
||||
|
||||
void _ExpandTextRow(SMALL_RECT& selectionRow) const;
|
||||
|
||||
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const;
|
||||
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const;
|
||||
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
|
||||
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const;
|
||||
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view& wordDelimiters) const;
|
||||
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view& wordDelimiters) const;
|
||||
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view& wordDelimiters) const;
|
||||
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view& wordDelimiters, const COORD lastCharPos) const;
|
||||
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view& wordDelimiters) const;
|
||||
void _PruneHyperlinks();
|
||||
|
||||
Microsoft::Console::Render::IRenderTarget& _renderTarget;
|
||||
std::vector<ROW> _storage;
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkCustomIdMapReverse;
|
||||
std::unordered_map<size_t, std::wstring> _idsAndPatterns;
|
||||
size_t _currentPatternId;
|
||||
TextAttribute _currentAttributes;
|
||||
UnicodeStorage _unicodeStorage;
|
||||
Cursor _cursor;
|
||||
void* _charBuffer;
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
uint16_t _currentHyperlinkId{ 1 };
|
||||
size_t _currentPatternId{ 0 };
|
||||
SHORT _firstRow{ 0 }; // indexes top row (not necessarily 0)
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
|
|
|
@ -51,8 +51,8 @@
|
|||
#include <vector>
|
||||
|
||||
// WIL
|
||||
#include <wil/Common.h>
|
||||
#include <wil/Result.h>
|
||||
#include <wil/common.h>
|
||||
#include <wil/result.h>
|
||||
#include <wil/nt_result_macros.h>
|
||||
#include <wil/resource.h>
|
||||
#include <wil/wistd_memory.h>
|
||||
|
|
|
@ -15,11 +15,11 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|||
class _bitmap_const_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = typename std::input_iterator_tag;
|
||||
using value_type = typename const til::rectangle;
|
||||
using difference_type = typename ptrdiff_t;
|
||||
using pointer = typename const til::rectangle*;
|
||||
using reference = typename const til::rectangle&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = const til::rectangle;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = const til::rectangle*;
|
||||
using reference = const til::rectangle&;
|
||||
|
||||
_bitmap_const_iterator(const dynamic_bitset<unsigned long long, Allocator>& values, til::rectangle rc, ptrdiff_t pos) :
|
||||
_values(values),
|
||||
|
|
Loading…
Reference in a new issue