Conversation
|
oh my god I love this image |
680f4e0 to
b70ef3d
Compare
2e5808f to
97c4048
Compare
ba60e7b to
34fc317
Compare
ca6498f to
6d2f72c
Compare
|
Codeflow link: |
| // - ulSize - The height of the cursor within this buffer | ||
| Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept : | ||
| _parentBuffer{ parentBuffer }, | ||
| _cPosition{ 0 }, |
There was a problem hiding this comment.
Are we sure this gets 0 initialized always? I know we used to have some weird OS-side bugs where memory wouldn't get 0 initialized. (apologies for needing a refresher on basic language concepts)
There was a problem hiding this comment.
Yes, with _cPosition a til::point now, it doesn't accept a single constructor parameter anymore - it needs either 0 (_cPosition{}) or 2 (_cPosition{ 0, 0 }). But if you write the former, you can drop it from the constructor list entirely, since it's already constructed like that by default anyways.
There was a problem hiding this comment.
To expand on that:
The old COORD _cPosition needed a manual initialization unlike til::point, because that type has no custom constructor which initializes X/Y to 0, nor does it use C++11's default member initializers (short X = 0;) like til::point does, so the default value for its members is "uninitialized" (which is UB).
The reason the existing code said _cPosition{ 0 } and not _cPosition{} is probably a carry-over from the C code, because C structs don't have default constructors - _cPosition{} is not valid C.
In C, if you pass less arguments than the struct has members, then the remaining fields will be set to 0. RECT{ 0 } is equivalent to RECT{ 0, 0, 0, 0 } and RECT{ 1 } is equivalent to RECT{ 1, 0, 0, 0 }. In C++, the compiler-generated constructor acts equivalent to C's with the addition of the default constructor {} which acts equivalent to { 0 }.
Since til::point has a custom constructor it gets no compiler-generated one and thus it can't be used with C-style constructor arguments anymore ({ 0 }).
| // Return Value: | ||
| // - the hashed coord | ||
| constexpr size_t operator()(const COORD& coord) const noexcept | ||
| constexpr size_t operator()(const til::point coord) const noexcept |
There was a problem hiding this comment.
Yeah. Technically it's beneficial to pass primitive structs like that by value at all times, because x64 calling conventions / ABIs pass them via registers. Any x64 ABI will pass the 8 byte large til::point within a single register (RCX on Windows, RDI everywhere else) which means that it's not just super fast, but also that no stack needs to be allocated, etc. This might not matter for functions that are only called from time to time, but some functions we got are called thousands of times per second. This is why I pass til::point and til::size by value throughout the project - it's just consistently very very performant.
Now the problem is that the Windows x64 ABI has a very unfortunate, very important flaw as compared to the SYSV ABI used by every single other x64 OS in the world and it makes me very very sad every single time I'm reminded of this. 🥲
...It can't pass structs larger than 8 byte via registers. With the SYSV ABI a 16 byte struct simply gets passed in the first two 8 byte large registers (RDI/RSI), but on Windows such arguments are passed as "hidden references/pointers" - the argument is still passed via a register (RCX), but the register now contains a pointer to the struct on the caller's stack. The callee will then copy it on their stack to create a by-value copy (via SSE's movups/movaps). Sometimes the optimizer can optimize the copy away, but usually it'll fail at doing so. The difference is a 4-5 fold increase in runtime cost for function calls, just by merely having a single by-value 16-byte struct as an argument.
This is why I pass til::rect and til::inclusive_rect consistently by-reference, because it prevents the VS 2022 (v143) compiler from creating such redundant, very costly stack copies on the callee side.
(I've been cooperating with DevDiv/Intel on optimizing these redundant stack copies away in the most common cases and it should hopefully land in a future VS 2022 update soonish. It reduces the overhead from 4-5x down to around 2x which is then about as good as passing it by-reference.)
There was a problem hiding this comment.
Wow that's incredibly thorough. We should have this saved somewhere (niksa.md maybe) as a reference that til::point&size should always be by value and rect always by ref.
Thanks!
There was a problem hiding this comment.
Yes, please do write this up as an addendum to Niksa.md
| Log::Comment(NoThrowString().Format(L"Original buffer size: %dx%d", oldSize.width, oldSize.height)); | ||
| Log::Comment(NoThrowString().Format(L"Original viewport: %dx%d", oldView.width, oldView.height)); | ||
| Log::Comment(NoThrowString().Format(L"Original buffer size: %dx%d", oldSize.X, oldSize.Y)); | ||
| Log::Comment(NoThrowString().Format(L"Original viewport: %dx%d", oldView.X, oldView.Y)); |
There was a problem hiding this comment.
If no other issues turn up I might just leave it as it is, because I'm going to fix all those members in a follow-up anyways.
| @@ -983,7 +983,7 @@ CATCH_RETURN(); | |||
| // - the text that the UiaTextRange encompasses | |||
| #pragma warning(push) | |||
| #pragma warning(disable : 26447) // compiler isn't filtering throws inside the try/catch | |||
| std::wstring UiaTextRangeBase::_getTextValue(std::optional<unsigned int> maxLength) const | |||
| std::wstring UiaTextRangeBase::_getTextValue(til::CoordType maxLength) const | |||
There was a problem hiding this comment.
if I could admit: i think optional captures the essence of this API better than "magic -1" does
There was a problem hiding this comment.
I understand where you're coming from, but this method exists only to implement ITextRangeProvider::GetText which says:
The maximum length of the string to return. Use -1 if no limit is required.
I feel like this is a direct translation of this API. Additionally I personally think that negative lengths are very common in C code (especially if cast to unsigned integers).
I chose this so that it generates the same |
DHowett
left a comment
There was a problem hiding this comment.
139/237! less than a hundo to go
DHowett
left a comment
There was a problem hiding this comment.
ALRIGHT! Get them concerns addressed and we are a GO!
| VERIFY_ARE_EQUAL(popup.Process(cookedReadData), static_cast<NTSTATUS>(CONSOLE_STATUS_WAIT_NO_BLOCK)); | ||
| // selection should have moved up a page | ||
| VERIFY_ARE_EQUAL(static_cast<short>(m_pHistory->GetNumberOfCommands()) - popup.Height() - 1, popup._currentCommand); | ||
| VERIFY_ARE_EQUAL(static_cast<til::CoordType>(m_pHistory->GetNumberOfCommands()) - popup.Height() - 1, popup._currentCommand); |
There was a problem hiding this comment.
this isn't exactly a coordinate either...
There was a problem hiding this comment.
The popup.Height() is in character cells and so I made it return a til::CoordType.
This change makes it so that the compiler doesn't complain that we should promote integers first before we add/subtract/multiply/divide them.
|
|
||
| VERIFY_IS_FALSE(areMarginsSet()); | ||
| VERIFY_ARE_EQUAL(COORD({ 0, 0 }), getRelativeCursorPosition()); | ||
| VERIFY_ARE_EQUAL(til::point(0, 0), getRelativeCursorPosition()); |
There was a problem hiding this comment.
Curious, using the constructor via function call syntax. You replaced similar thing with point{}; should we here?
There was a problem hiding this comment.
The VERIFY_ARE_EQUAL macro blows up if you use curly brackets inside it. Not kidding. IIRC the ({ 0, 0 }) doesn't work because the constructor is explicit and doesn't take a single parameter list argument (unlike structs).
| } | ||
|
|
||
| void FillBothCoordsSameRandom(COORD* pcoordA, COORD* pcoordB) | ||
| void FillBothCoordsSameRandom(til::point* pcoordA, til::point* pcoordB) |
There was a problem hiding this comment.
This seems like a very silly way to do a = rand(); b = a;
| // Return Value: | ||
| // - A vector of rectangles representing the regions to select, line by line. | ||
| std::vector<SMALL_RECT> Renderer::_GetSelectionRects() const | ||
| std::vector<til::rect> Renderer::_GetSelectionRects() const |
There was a problem hiding this comment.
Double check this code. I saw that INSIDE the renderer they're exclusive now, but via RenderData and OUTSIDE the renderer they're inclusive. That's fine, but look at line R1284 -- we bump up the inclusive SR to be exclusive, and then we construct a til::rect out of it making it exclusive again...
| oldRows.visibleViewportTop = newVisibleTop; | ||
|
|
||
| const std::optional<short> oldViewStart{ oldViewportTop }; | ||
| const std::optional oldViewStart{ oldViewportTop }; |
|
Oh no!
|
|
Hello @DHowett! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
This is a follow-up of #13025 to make the members of `til::point/size/rect` uniform and consistent without the use of `unions`. The only file that has any changes is `src/host/getset.cpp` where an if condition was simplified. ## Validation Steps Performed * Host unit tests ✅ * Host feature tests ✅ * ControlCore feature tests ✅


Previously this project used a great variety of types to present text buffer
coordinates:
short,unsigned short,int,unsigned int,size_t,ptrdiff_t,COORD/SMALL_RECT(akashort), and more.This massive commit migrates almost all use of those types over to the
centralized types
til::point/size/rect/inclusive_rectand theirunderlying type
til::CoordType(akaint32_t).Due to the size of the changeset and statistics I expect it to contain bugs.
The biggest risk I see is that some code potentially, maybe implicitly, expected
arithmetic to be mod 2^16 and that this code now allows it to be mod 2^32.
Any narrowing into
shortlater on would then throw exceptions.PR Checklist
Validation Steps Performed
Casual usage of OpenConsole and Windows Terminal. ✅