Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use til::some<T,N> to replace the SomeViewports class #4174

Merged
2 commits merged into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions src/inc/til.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,11 @@

#pragma once

#include "til/at.h"
#include "til/some.h"

namespace til // Terminal Implementation Library. Also: "Today I Learned"
{
// The at function declares that you've already sufficiently checked that your array access
// is in range before retrieving an item inside it at an offset.
// This is to save double/triple/quadruple testing in circumstances where you are already
// pivoting on the length of a set and now want to pull elements out of it by offset
// without checking again.
// gsl::at will do the check again. As will .at(). And using [] will have a warning in audit.
template<class T>
constexpr auto at(T& cont, const size_t i) -> decltype(cont[cont.size()])
{
#pragma warning(suppress : 26482) // Suppress bounds.2 check for indexing with constant expressions
#pragma warning(suppress : 26446) // Suppress bounds.4 check for subscript operator.
return cont[i];
}
}

// These sit outside the namespace because they sit outside for WIL too.
Expand Down
21 changes: 21 additions & 0 deletions src/inc/til/at.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#pragma once

namespace til
{
// The at function declares that you've already sufficiently checked that your array access
// is in range before retrieving an item inside it at an offset.
// This is to save double/triple/quadruple testing in circumstances where you are already
// pivoting on the length of a set and now want to pull elements out of it by offset
// without checking again.
// gsl::at will do the check again. As will .at(). And using [] will have a warning in audit.
template<class T>
constexpr auto at(T& cont, const size_t i) -> decltype(cont[cont.size()])
{
#pragma warning(suppress : 26482) // Suppress bounds.2 check for indexing with constant expressions
#pragma warning(suppress : 26446) // Suppress bounds.4 check for subscript operator.
return cont[i];
}
}
4 changes: 2 additions & 2 deletions src/inc/til/some.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
_outOfRange();
}

_array[_used] = val;
til::at(_array, _used) = val;

++_used;
}
Expand All @@ -168,7 +168,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"

--_used;

_array[_used] = 0;
til::at(_array, _used) = 0;
}

[[noreturn]] void _invalidArg() const
Expand Down
28 changes: 5 additions & 23 deletions src/types/inc/viewport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ Author(s):

namespace Microsoft::Console::Types
{
struct SomeViewports;
class Viewport;

using SomeViewports = til::some<Viewport, 4>;

class Viewport final
{
public:
~Viewport() {}
constexpr Viewport() noexcept :
_sr({ 0, 0, -1, -1 }){};
Viewport(const Viewport& other) noexcept;
Viewport(Viewport&&) = default;
Viewport& operator=(const Viewport&) & = default;
Expand Down Expand Up @@ -125,28 +129,6 @@ namespace Microsoft::Console::Types
friend class ViewportTests;
#endif
};

struct SomeViewports final
{
unsigned char used{ 0 };
std::array<Viewport, 4> viewports{ Viewport::Empty(), Viewport::Empty(), Viewport::Empty(), Viewport::Empty() };

// These two methods are to make this vaguely look like a std::vector.

// Size is the number of viewports that are valid inside this structure
size_t size() const noexcept { return used; }

// At retrieves a viewport at a particular index. If you retrieve beyond the valid size(),
// it will throw std::out_of_range
const Viewport& at(size_t index) const
{
if (index >= used)
{
throw std::out_of_range("Access attempted beyond valid size.");
}
return viewports.at(index);
}
};
}

inline COORD operator-(const COORD& a, const COORD& b) noexcept
Expand Down
14 changes: 8 additions & 6 deletions src/types/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Viewport::Viewport(const Viewport& other) noexcept :

Viewport Viewport::Empty() noexcept
{
return Viewport({ 0, 0, -1, -1 });
return Viewport();
}

Viewport Viewport::FromInclusive(const SMALL_RECT sr) noexcept
Expand Down Expand Up @@ -895,6 +895,7 @@ Viewport Viewport::ToOrigin() const noexcept
// that was covered by `main` before the regional area of `removeMe` was taken out.
// - You must check that each viewport .IsValid() before using it.
[[nodiscard]] SomeViewports Viewport::Subtract(const Viewport& original, const Viewport& removeMe) noexcept
try
{
SomeViewports result;

Expand All @@ -907,7 +908,7 @@ Viewport Viewport::ToOrigin() const noexcept
if (!intersection.IsValid())
{
// Just put the original rectangle into the results and return early.
result.viewports.at(result.used++) = original;
result.push_back(original);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler also complains about this throwing exception. But logically this method does not throw anything. And I'm surprised that the Substract is not used anywhere. Should I make it non-noexcept or just catch the exception inside it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so this is an interesting one. push_back on some can throw an exception if it's full, so technically this one can throw an exception.
We know through static analysis (like, with our eyes) that it will never throw...

@miniksa what do you think about cases like this? This will never except until 4 becomes less than 3...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nnnnn. A few ideas all of which I don't really like....

  1. Make it except: That then pollutes all callers. Yuck.
  2. Catch it: Seems obnoxious to write a whole try/CATCH_LOG or try/CATCH_FAIL_FAST around it.
  3. Suppress it: A noexcept that throws technically goes straight to std::terminate which is more or less the same as try/CATCH_FAIL_FAST.
  4. Add another accessor onto til::some. I can't think of one that wouldn't also suffer from this. If you do it with just unchecked array access, now you have a different warning and need til::at. If you do it with some.at(), that would presumably throw out of bounds too. If we add any other method, then it doesn't look quite like the STL collections it is mocking.

I'm leaning toward 2. I hate 1 and 4. I really don't like 3 as it's implicit instead of explicit like 2.
Doing 2 is also generally what we do around the codebase for this problem.

Also, this applies to .ToOrigin() below as well, right?

}
// If the original rectangle matches the intersection, there is nothing to return.
else if (original != intersection)
Expand Down Expand Up @@ -1003,27 +1004,28 @@ Viewport Viewport::ToOrigin() const noexcept

if (top.IsValid())
{
result.viewports.at(result.used++) = top;
result.push_back(top);
}

if (bottom.IsValid())
{
result.viewports.at(result.used++) = bottom;
result.push_back(bottom);
}

if (left.IsValid())
{
result.viewports.at(result.used++) = left;
result.push_back(left);
}

if (right.IsValid())
{
result.viewports.at(result.used++) = right;
result.push_back(right);
}
}

return result;
}
CATCH_FAIL_FAST()

// Method Description:
// - Returns true if the rectangle described by this Viewport has internal space
Expand Down