Skip to content
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
12 changes: 6 additions & 6 deletions docs/headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,16 @@ See [SL.str.5: Use `std::byte` to refer to byte values that do not necessarily r
### Non-member functions

```cpp
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept;

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte operator<<(byte b, IntegerType shift) noexcept;

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept;

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte operator>>(byte b, IntegerType shift) noexcept;
```

Expand Down Expand Up @@ -134,7 +134,7 @@ constexpr byte operator~(byte b) noexcept;
Bitwise negation of a `byte`. Flips all bits. Zeroes become ones, ones become zeroes.

```cpp
template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr IntegerType to_integer(byte b) noexcept;
```

Expand Down Expand Up @@ -310,7 +310,7 @@ auto make_not_null(T&& t) noexcept;
Creates a `gsl::not_null` object, deducing the target type from the type of the argument.

```cpp
template <typename T, typename = std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
void swap(not_null<T>& a, not_null<T>& b);
```

Expand Down
10 changes: 5 additions & 5 deletions include/gsl/byte
Original file line number Diff line number Diff line change
Expand Up @@ -91,25 +91,25 @@ enum class byte_may_alias byte : unsigned char
{
};

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
{
return b = byte(static_cast<unsigned char>(b) << shift);
}

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte operator<<(byte b, IntegerType shift) noexcept
{
return byte(static_cast<unsigned char>(b) << shift);
}

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
{
return b = byte(static_cast<unsigned char>(b) >> shift);
}

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte operator>>(byte b, IntegerType shift) noexcept
{
return byte(static_cast<unsigned char>(b) >> shift);
Expand Down Expand Up @@ -147,7 +147,7 @@ constexpr byte operator^(byte l, byte r) noexcept

constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }

template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr IntegerType to_integer(byte b) noexcept
{
return static_cast<IntegerType>(b);
Expand Down
2 changes: 1 addition & 1 deletion include/gsl/pointers
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ private:
T ptr_;
};

template <typename T, typename = std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
void swap(not_null<T>& a, not_null<T>& b)
{
a.swap(b);
Expand Down
45 changes: 45 additions & 0 deletions tests/byte_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#define GSL_USE_STD_BYTE 0
#include <gsl/byte> // for to_byte, to_integer, byte, operator&, ope...

#include <type_traits>
#include <utility>

using namespace std;
using namespace gsl;

Expand Down Expand Up @@ -128,6 +131,48 @@ TEST(byte_tests, aliasing)
EXPECT_TRUE(res == i);
}

#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l

template <typename U, typename = void>
static constexpr bool LShiftCompilesFor = false;
template <typename U>
static constexpr bool LShiftCompilesFor<
U, void_t<decltype(gsl::operator<< <float>(declval<gsl::byte>(), declval<U>()))>> = true;
static_assert(!LShiftCompilesFor<float>, "!LShiftCompilesFor<float>");

template <typename U, typename = void>
static constexpr bool RShiftCompilesFor = false;
template <typename U>
static constexpr bool RShiftCompilesFor<
U, void_t<decltype(gsl::operator>> <U>(declval<gsl::byte>(), declval<U>()))>> = true;
static_assert(!RShiftCompilesFor<float>, "!RShiftCompilesFor<float>");

template <typename U, typename = void>
static constexpr bool LShiftAssignCompilesFor = false;
template <typename U>
static constexpr bool LShiftAssignCompilesFor<
U, void_t<decltype(gsl::operator<<= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
static_assert(!LShiftAssignCompilesFor<float>, "!LShiftAssignCompilesFor<float>");

template <typename U, typename = void>
static constexpr bool RShiftAssignCompilesFor = false;
template <typename U>
static constexpr bool RShiftAssignCompilesFor<
U, void_t<decltype(gsl::operator>>= <U>(declval<gsl::byte&>(), declval<U>()))>> = true;
static_assert(!RShiftAssignCompilesFor<float>, "!RShiftAssignCompilesFor<float>");

template <typename U, typename = void>
static constexpr bool ToIntegerCompilesFor = false;
template <typename U>
static constexpr bool
ToIntegerCompilesFor<U, void_t<decltype(gsl::to_integer<U>(gsl::byte{}))>> = true;
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");

} // namespace

#ifdef CONFIRM_COMPILATION_ERRORS
Expand Down
41 changes: 41 additions & 0 deletions tests/pointers_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
#include <gsl/pointers>

#include <memory>
#include <type_traits>
#include <utility>

namespace
{
// Custom pointer type that can be used for gsl::not_null, but for which these cannot be swapped.
struct NotMoveAssignableCustomPtr
{
NotMoveAssignableCustomPtr() = default;
NotMoveAssignableCustomPtr(const NotMoveAssignableCustomPtr&) = default;
NotMoveAssignableCustomPtr& operator=(const NotMoveAssignableCustomPtr&) = default;
NotMoveAssignableCustomPtr(NotMoveAssignableCustomPtr&&) = default;
NotMoveAssignableCustomPtr& operator=(NotMoveAssignableCustomPtr&&) = delete;

bool operator!=(std::nullptr_t) const { return true; }

int dummy{}; // Without this clang warns, that NotMoveAssignableCustomPtr() is unneeded
};

TEST(pointers_test, swap)
{
Expand All @@ -17,5 +35,28 @@ TEST(pointers_test, swap)

EXPECT_TRUE(*a == 1);
EXPECT_TRUE(*b == 0);

// Make sure our custom ptr can be used with not_null. The shared_pr is to prevent "unused"
// compiler warnings.
const auto shared_custom_ptr{std::make_shared<NotMoveAssignableCustomPtr>()};
gsl::not_null<NotMoveAssignableCustomPtr> c{*shared_custom_ptr};
EXPECT_TRUE(c.get() != nullptr);
}

#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l

template <typename U, typename = void>
static constexpr bool SwapCompilesFor = false;
template <typename U>
static constexpr bool
SwapCompilesFor<U, void_t<decltype(gsl::swap<U>(std::declval<gsl::not_null<U>&>(),
std::declval<gsl::not_null<U>&>()))>> = true;
static_assert(!SwapCompilesFor<NotMoveAssignableCustomPtr>,
"!SwapCompilesFor<NotMoveAssignableCustomPtr>");

} // namespace
9 changes: 7 additions & 2 deletions tests/span_compatibility_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1005,12 +1005,18 @@ static_assert(std::is_convertible<const std::array<int, 3>&, gsl::span<const int
"std::is_convertible<const std::array<int, 3>&, gsl::span<const int>>");

#if __cplusplus >= 201703l
using std::void_t;
#else // __cplusplus >= 201703l
template <class...>
using void_t = void;
#endif // __cplusplus < 201703l

template <typename U, typename = void>
static constexpr bool AsWritableBytesCompilesFor = false;

template <typename U>
static constexpr bool
AsWritableBytesCompilesFor<U, void_t<decltype(as_writable_bytes(declval<U>()))>> = true;
AsWritableBytesCompilesFor<U, ::void_t<decltype(as_writable_bytes(declval<U>()))>> = true;

static_assert(AsWritableBytesCompilesFor<gsl::span<int>>,
"AsWritableBytesCompilesFor<gsl::span<int>>");
Expand All @@ -1020,4 +1026,3 @@ static_assert(!AsWritableBytesCompilesFor<gsl::span<const int>>,
"!AsWritableBytesCompilesFor<gsl::span<const int>>");
static_assert(!AsWritableBytesCompilesFor<gsl::span<const int, 9>>,
"!AsWritableBytesCompilesFor<gsl::span<const int, 9>>");
#endif // __cplusplus >= 201703l
Loading