clang-format improvements (#1251)

* clang-format improvements

- Add a clang-format linter check to the PR pipeline
- Apply clang-format to files where the linter initially failed
- Remove `CommentPragmas` from `.clang-format`
- Remove all `// clang-format off` and `// NO-FORMAT` as they are not needed
- Remove a commented out `GSL_SUPPRESS`

* clang-format 20

* pipeline fail

* Update .github/workflows/clang-format.yml

Co-authored-by: Carson Radtke <nosrac925@gmail.com>

* output used clang-format version

* installed version is 18 which replaces "GSL_SUPPRESS(bounds.1)" with "GSL_SUPPRESS(bounds .1)"

* only include/gsl, not include

to prevent formatting of include/CMakeLists.txt

* apply clang-format[-20]

In a VS2026 developer command prompt I ran `clang-format -i include\gsl\* --assume-filename x.cpp`. This was necessary because VS GUI does not format files without an extension :(. Please note that `--assume-filename` is necessary here, otherwise the files will not be formatted. Surprisingly the behaviour for the formatter differs from the behaviour of `lang-format(-20) --dry-run --Werror include/gsl/*` where clang-format recognizes that the files is C++.

* change "#if 0" back to original version with comments only

* formatting scripts for windows and linux

for linux with linter (shfmt and shellcheck)

* add WhitespaceSensitiveMacros: [GSL_SUPPRESS]

* provide path for clang-format (Windows)

Currently not clear to me:
On my personal computer at home, when I start "Developer Command Prompt for VS18", I can run `clang-format` without providing the path.
On my managed (domain) company computer, when I start "Developer Command Prompt for VS18", I can NOT run `clang-format` without providing the path. I need to call `"%VCINSTALLDIR%Tools\Llvm\bin\clang-format"`.
I have no idea what the difference is. At least the version `"%VCINSTALLDIR%Tools\Llvm\bin\clang-format"` works on both computers, so I add the path.

---------

Co-authored-by: Werner Henze <w.henze@avm.de>
Co-authored-by: Carson Radtke <nosrac925@gmail.com>
Co-authored-by: Werner Henze <werner.henze+gitcommits@posteo.de>
This commit is contained in:
Werner Henze 2026-06-05 14:45:10 +02:00 committed by GitHub
parent f3c5967126
commit b2f6bec48e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 303 additions and 239 deletions

View file

@ -31,4 +31,4 @@ AlignConsecutiveAssignments: false
AlignTrailingComments: true
SpaceAfterCStyleCast: true
CommentPragmas: '^ NO-FORMAT:'
WhitespaceSensitiveMacros: [GSL_SUPPRESS]

39
.github/workflows/clang-format.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: Code Formatting
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
env:
CLANG_VERSION: "20"
jobs:
clang-format:
name: Run clang-format
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# Install the exact clang-format binary
- name: Install clang-format
run: |
sudo apt install clang-format-${{ env.CLANG_VERSION }}
# Prints the version of clang-format being used
- name: Log clang-format version
run: clang-format-${{ env.CLANG_VERSION }} --version
# Runs clang-format over the repository codebase
- name: Check format
run: |
{
find include/gsl -type f
find tests -type f \( -name '*.cpp' -o -name '*.h' \)
} | xargs clang-format-${{ env.CLANG_VERSION }} --dry-run --Werror

View file

@ -0,0 +1,32 @@
name: Shell script linter
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
clang-format:
name: Run shfmt and shellcheck
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# Install the needed binaries
- name: Install shfmt and shellcheck
run: |
sudo apt install shfmt shellcheck
- name: Check format
run: |
find scripts -type f -name '*.sh' -exec shfmt -l {} \;
- name: Run shellcheck
run: |
find scripts -type f -name '*.sh' -exec shellcheck {} \;

View file

@ -48,9 +48,7 @@ void copy(span<SrcElementType, SrcExtent> src, span<DestElementType, DestExtent>
"Source range is longer than target range");
Expects(dest.size() >= src.size());
// clang-format off
GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(stl.1)
std::copy_n(src.data(), src.size(), dest.data());
}

View file

@ -93,9 +93,7 @@ namespace details
typedef void(__cdecl* terminate_handler)();
// clang-format off
GSL_SUPPRESS(f.6) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.6)
[[noreturn]] inline void __cdecl default_terminate_handler()
{
__fastfail(RANGE_CHECKS_FAILURE);

View file

@ -82,11 +82,13 @@ namespace gsl
{
#if GSL_USE_STD_BYTE
namespace impl {
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as would be the case when we used gsl::byte.
// Users of GSL should only use gsl::byte, not gsl::impl::byte.
namespace impl
{
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as
// would be the case when we used gsl::byte. Users of GSL should only use gsl::byte, not
// gsl::impl::byte.
using byte = std::byte;
}
} // namespace impl
using byte GSL_DEPRECATED("Use std::byte instead.") = std::byte;
@ -100,11 +102,13 @@ enum class byte_may_alias byte : unsigned char
{
};
namespace impl {
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as would be the case when we used gsl::byte.
// Users of GSL should only use gsl::byte, not gsl::impl::byte.
namespace impl
{
// impl::byte is used by gsl::as_bytes so our own code does not trigger a deprecation warning as
// would be the case when we used gsl::byte. Users of GSL should only use gsl::byte, not
// gsl::impl::byte.
using byte = gsl::byte;
}
} // namespace impl
template <class IntegerType, std::enable_if_t<std::is_integral<IntegerType>::value, bool> = true>
constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
@ -170,13 +174,11 @@ constexpr IntegerType to_integer(byte b) noexcept
#endif // GSL_USE_STD_BYTE
template <typename T>
// NOTE: need suppression since c++14 does not allow "return {t}"
// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
constexpr gsl::impl::byte to_byte(T t) noexcept
{
static_assert(std::is_same<T, unsigned char>::value,
static_assert(
std::is_same<T, unsigned char>::value,
"gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
"If you are calling to_byte with an integer constant use: gsl::to_byte<t>() version.");
return gsl::impl::byte(t);

View file

@ -23,8 +23,8 @@
#include "./byte" // byte
#include "./pointers" // owner, not_null
#include "./span" // span
#include "./zstring" // zstring
#include "./util" // finally()/narrow_cast()...
#include "./zstring" // zstring
#ifdef __cpp_exceptions
#include "./narrow" // narrow()

View file

@ -28,24 +28,24 @@ struct narrowing_error : public std::exception
// narrow() : a checked version of narrow_cast() that throws if the cast changed the value
template <class T, class U, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur
GSL_SUPPRESS(type.1)
GSL_SUPPRESS(es.46) // The warning suggests that a floating->unsigned conversion can occur
// in the static_cast below, and that gsl::narrow should be used instead.
// Suppress this warning, since gsl::narrow is defined in terms of
// static_cast
// clang-format on
constexpr T narrow(U u)
{
constexpr const bool is_different_signedness =
(std::is_signed<T>::value != std::is_signed<U>::value);
GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow
GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow
GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
const T t = narrow_cast<T>(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type
// and cannot fit into the destination integral type), the resultant behavior is benign on the platforms
// that we target (i.e., no hardware trap representations are hit).
GSL_SUPPRESS(es.103) // don't overflow
GSL_SUPPRESS(es.104) // don't underflow
GSL_SUPPRESS(p.2) // don't rely on undefined behavior
const T t = narrow_cast<T>(
u); // While this is technically undefined behavior in some cases (i.e., if the source value
// is of floating-point type and cannot fit into the destination integral type), the
// resultant behavior is benign on the platforms that we target (i.e., no hardware trap
// representations are hit).
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic push
@ -64,17 +64,11 @@ GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
}
template <class T, class U, typename std::enable_if<!std::is_arithmetic<T>::value>::type* = nullptr>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
constexpr T narrow(U u)
GSL_SUPPRESS(type.1) constexpr T narrow(U u)
{
const T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u)
{
throw narrowing_error{};
}
if (static_cast<U>(t) != u) { throw narrowing_error{}; }
return t;
}

View file

@ -48,15 +48,16 @@ namespace details
{
};
// Resolves to the more efficient of `const T` or `const T&`, in the context of returning a const-qualified value
// of type T.
// Resolves to the more efficient of `const T` or `const T&`, in the context of returning a
// const-qualified value of type T.
//
// Copied from cppfront's implementation of the CppCoreGuidelines F.16 (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#rf-in)
// Copied from cppfront's implementation of the CppCoreGuidelines F.16
// (https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#rf-in)
template <typename T>
using value_or_reference_return_t = std::conditional_t<
sizeof(T) <= 2*sizeof(void*) && std::is_trivially_copy_constructible<T>::value,
const T,
const T&>;
using value_or_reference_return_t =
std::conditional_t<sizeof(T) <= 2 * sizeof(void*) &&
std::is_trivially_copy_constructible<T>::value,
const T, const T&>;
} // namespace details
@ -72,9 +73,10 @@ using unique_ptr GSL_DEPRECATED("Use std::unique_ptr instead") = std::unique_ptr
//
// owner
//
// `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw pointers that own memory.
// Ideally such code should be restricted to the implementation of low-level abstractions. `gsl::owner` can also be used
// as a stepping point in converting legacy code to use more modern RAII constructs, such as smart pointers.
// `gsl::owner<T>` is designed as a safety mechanism for code that must deal directly with raw
// pointers that own memory. Ideally such code should be restricted to the implementation of
// low-level abstractions. `gsl::owner` can also be used as a stepping point in converting legacy
// code to use more modern RAII constructs, such as smart pointers.
//
// T must be a pointer type
// - disallow construction from any type other than pointer type
@ -105,19 +107,23 @@ public:
using element_type = T;
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::forward<U>(u))
constexpr not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value)
: ptr_(std::forward<U>(u))
{
Expects(ptr_ != nullptr);
}
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : ptr_(std::move(u))
constexpr not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value)
: ptr_(std::move(u))
{
Expects(ptr_ != nullptr);
}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null(other.get())
constexpr not_null(const not_null<U>& other) noexcept(
std::is_nothrow_move_constructible<T>::value)
: not_null(other.get())
{}
not_null(const not_null& other) = default;
@ -151,7 +157,9 @@ private:
T ptr_;
};
template <typename T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value, bool> = true>
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) noexcept
{
a.swap(b);
@ -189,15 +197,15 @@ constexpr auto operator!=(const not_null<T>& lhs,
}
template <class T, class U>
constexpr auto operator<(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(std::less<>{}(lhs.get(), rhs.get())))
-> decltype(std::less<>{}(lhs.get(), rhs.get()))
constexpr auto operator<(const not_null<T>& lhs, const not_null<U>& rhs) noexcept(
noexcept(std::less<>{}(lhs.get(), rhs.get()))) -> decltype(std::less<>{}(lhs.get(), rhs.get()))
{
return std::less<>{}(lhs.get(), rhs.get());
}
template <class T, class U>
constexpr auto operator<=(const not_null<T>& lhs,
constexpr auto
operator<=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(std::less_equal<>{}(lhs.get(), rhs.get())))
-> decltype(std::less_equal<>{}(lhs.get(), rhs.get()))
{
@ -205,7 +213,8 @@ constexpr auto operator<=(const not_null<T>& lhs,
}
template <class T, class U>
constexpr auto operator>(const not_null<T>& lhs,
constexpr auto
operator>(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(std::greater<>{}(lhs.get(), rhs.get())))
-> decltype(std::greater<>{}(lhs.get(), rhs.get()))
{
@ -213,7 +222,8 @@ constexpr auto operator>(const not_null<T>& lhs,
}
template <class T, class U>
constexpr auto operator>=(const not_null<T>& lhs,
constexpr auto
operator>=(const not_null<T>& lhs,
const not_null<U>& rhs) noexcept(noexcept(std::greater_equal<>{}(lhs.get(), rhs.get())))
-> decltype(std::greater_equal<>{}(lhs.get(), rhs.get()))
{
@ -230,9 +240,10 @@ not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
template <class T>
not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
// T is conceptually a pointer so we don't have to worry about it being a reference and violating std::hash requirements
template <class T, class U = typename T::element_type, bool = std::is_default_constructible<std::hash<U>>::value>
// T is conceptually a pointer so we don't have to worry about it being a reference and violating
// std::hash requirements
template <class T, class U = typename T::element_type,
bool = std::is_default_constructible<std::hash<U>>::value>
struct not_null_hash
{
std::size_t operator()(const T& value) const noexcept { return std::hash<U>{}(value.get()); }
@ -282,24 +293,32 @@ class strict_not_null : public not_null<T>
{
public:
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr explicit strict_not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::forward<U>(u))
constexpr explicit strict_not_null(U&& u) noexcept(std::is_nothrow_move_constructible<T>::value)
: not_null<T>(std::forward<U>(u))
{}
template <typename = std::enable_if_t<!std::is_same<std::nullptr_t, T>::value>>
constexpr explicit strict_not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(std::move(u))
constexpr explicit strict_not_null(T u) noexcept(std::is_nothrow_move_constructible<T>::value)
: not_null<T>(std::move(u))
{}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr strict_not_null(const not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
constexpr strict_not_null(const not_null<U>& other) noexcept(
std::is_nothrow_move_constructible<T>::value)
: not_null<T>(other)
{}
template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
constexpr strict_not_null(const strict_not_null<U>& other) noexcept(std::is_nothrow_move_constructible<T>::value) : not_null<T>(other)
constexpr strict_not_null(const strict_not_null<U>& other) noexcept(
std::is_nothrow_move_constructible<T>::value)
: not_null<T>(other)
{}
// To avoid invalidating the "not null" invariant, the contained pointer is actually copied
// instead of moved. If it is a custom pointer, its constructor could in theory throw exceptions.
strict_not_null(strict_not_null&& other) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
// instead of moved. If it is a custom pointer, its constructor could in theory throw
// exceptions.
strict_not_null(strict_not_null&& other) noexcept(
std::is_nothrow_copy_constructible<T>::value) = default;
strict_not_null(const strict_not_null& other) = default;
strict_not_null& operator=(const strict_not_null& other) = default;
strict_not_null& operator=(const not_null<T>& other)

View file

@ -163,9 +163,7 @@ namespace details
constexpr span_iterator& operator++() noexcept
{
Expects(current_ != end_);
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
++current_;
return *this;
}
@ -196,9 +194,7 @@ namespace details
if (n != 0) Expects(begin_ && current_ && end_);
if (n > 0) Expects(end_ - current_ >= n);
if (n < 0) Expects(current_ - begin_ >= -n);
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
current_ += n;
return *this;
}
@ -315,9 +311,7 @@ namespace details
if (n < 0) Expects(current_ - begin_ >= -n);
}
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
constexpr pointer _Unwrapped() const noexcept
{ // after seeking *this to a high water mark, or using one of the
// _Verify_xxx functions above, unwrap this span_iterator to a raw
@ -332,9 +326,7 @@ namespace details
#else
static constexpr bool _Unwrap_when_unverified = false;
#endif
// clang-format off
GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
// clang-format on
GSL_SUPPRESS(con.3) // TODO: false positive
constexpr void _Seek_to(const pointer p) noexcept
{ // adjust the position of *this to previously verified location p
// after _Unwrapped
@ -349,7 +341,8 @@ namespace details
template <typename Ptr>
friend struct std::pointer_traits;
};
}} // namespace gsl::details
} // namespace details
} // namespace gsl
namespace std
{
@ -364,7 +357,10 @@ struct pointer_traits<::gsl::details::span_iterator<Type>>
};
} // namespace std
namespace gsl { namespace details {
namespace gsl
{
namespace details
{
template <std::size_t Ext>
class extent_type
{
@ -589,10 +585,7 @@ public:
}
template <std::size_t Count>
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
constexpr span<element_type, Count> last() const noexcept
GSL_SUPPRESS(bounds.1) constexpr span<element_type, Count> last() const noexcept
{
static_assert(Extent == dynamic_extent || Count <= Extent,
"last() cannot extract more elements from a span than it contains.");
@ -601,10 +594,7 @@ public:
}
template <std::size_t Offset, std::size_t Count = dynamic_extent>
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
constexpr auto subspan() const noexcept ->
GSL_SUPPRESS(bounds.1) constexpr auto subspan() const noexcept ->
typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
{
static_assert(Extent == dynamic_extent || (Extent >= Offset && (Count == dynamic_extent ||
@ -642,9 +632,7 @@ public:
constexpr bool empty() const noexcept { return size() == 0; }
// [span.elem], span element access
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
constexpr reference operator[](size_type idx) const noexcept
{
Expects(idx < size());
@ -669,18 +657,14 @@ public:
constexpr iterator begin() const noexcept
{
const auto data = storage_.data();
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
return {data, data + size(), data};
}
constexpr iterator end() const noexcept
{
const auto data = storage_.data();
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
const auto endData = data + storage_.size();
return {data, endData, endData};
}
@ -693,9 +677,7 @@ public:
constexpr pointer _Unchecked_begin() const noexcept { return data(); }
constexpr pointer _Unchecked_end() const noexcept
{
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
return data() + size();
}
#endif // _MSC_VER
@ -752,9 +734,7 @@ private:
return tmp.subspan(offset, count);
}
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(bounds.1)
constexpr span<element_type, dynamic_extent>
make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
{
@ -792,7 +772,9 @@ span(const Container&) -> span<Element>;
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
#if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated" // Bug in clang-cl.exe which raises a C++17 -Wdeprecated warning about this static constexpr workaround in C++14 mode.
#pragma clang diagnostic ignored \
"-Wdeprecated" // Bug in clang-cl.exe which raises a C++17 -Wdeprecated warning about this
// static constexpr workaround in C++14 mode.
#endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
template <class ElementType, std::size_t Extent>
constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
@ -827,11 +809,10 @@ template <class ElementType, std::size_t Extent>
span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
as_bytes(span<ElementType, Extent> s) noexcept
{
using type = span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
using type =
span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return type{reinterpret_cast<const gsl::impl::byte*>(s.data()), s.size_bytes()};
}
@ -842,9 +823,7 @@ as_writable_bytes(span<ElementType, Extent> s) noexcept
{
using type = span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return type{reinterpret_cast<gsl::impl::byte*>(s.data()), s.size_bytes()};
}

View file

@ -21,8 +21,8 @@
#include <array>
#include <cstddef> // for ptrdiff_t, size_t
#include <limits> // for numeric_limits
#include <initializer_list> // for initializer_list
#include <limits> // for numeric_limits
#include <type_traits> // for is_signed, integral_constant
#include <utility> // for exchange, forward
@ -103,7 +103,10 @@ public:
explicit final_action(const F& ff) noexcept : f{ff} {}
explicit final_action(F&& ff) noexcept : f{std::move(ff)} {}
~final_action() noexcept { if (invoke) f(); }
~final_action() noexcept
{
if (invoke) f();
}
final_action(final_action&& other) noexcept
: f(std::move(other.f)), invoke(std::exchange(other.invoke, false))
@ -127,10 +130,7 @@ GSL_NODISCARD auto finally(F&& f) noexcept
// narrow_cast(): a searchable way to do narrowing casts of values
template <class T, class U>
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
constexpr T narrow_cast(U&& u) noexcept
GSL_SUPPRESS(type.1) constexpr T narrow_cast(U&& u) noexcept
{
return static_cast<T>(std::forward<U>(u));
}
@ -139,23 +139,17 @@ GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector
//
template <class T, std::size_t N>
// clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on
constexpr T& at(T (&arr)[N], const index i)
GSL_SUPPRESS(bounds.4) GSL_SUPPRESS(bounds.2) constexpr T& at(T (&arr)[N], const index i)
{
static_assert(N <= static_cast<std::size_t>((std::numeric_limits<std::ptrdiff_t>::max)()), "We only support arrays up to PTRDIFF_MAX bytes.");
static_assert(N <= static_cast<std::size_t>((std::numeric_limits<std::ptrdiff_t>::max)()),
"We only support arrays up to PTRDIFF_MAX bytes.");
Expects(i >= 0 && i < narrow_cast<index>(N));
return arr[narrow_cast<std::size_t>(i)];
}
template <class Cont>
// clang-format off
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
// clang-format on
constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()])
GSL_SUPPRESS(bounds.4) GSL_SUPPRESS(bounds.2) constexpr auto at(Cont& cont, const index i)
-> decltype(cont[cont.size()])
{
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
using size_type = decltype(cont.size());
@ -163,17 +157,18 @@ GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
}
template <class T>
// clang-format off
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
// clang-format on
constexpr T at(const std::initializer_list<T> cont, const index i)
GSL_SUPPRESS(bounds.1) constexpr T at(const std::initializer_list<T> cont, const index i)
{
Expects(i >= 0 && i < narrow_cast<index>(cont.size()));
return *(cont.begin() + i);
}
template <class T, std::enable_if_t<std::is_move_assignable<T>::value && std::is_move_constructible<T>::value>>
void swap(T& a, T& b) { std::swap(a, b); }
template <class T, std::enable_if_t<std::is_move_assignable<T>::value &&
std::is_move_constructible<T>::value>>
void swap(T& a, T& b)
{
std::swap(a, b);
}
#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L
template <class T, std::size_t extent = std::dynamic_extent>

View file

@ -0,0 +1,13 @@
@echo off
setlocal enabledelayedexpansion
"%VCINSTALLDIR%Tools\Llvm\bin\clang-format" -version
if %errorlevel% neq 0 (
echo [ERROR] clang-format not found, script should be called from a visual studio developer command prompt.
exit /b %errorlevel%
)
for %%f in (include\gsl\* tests\*.h tests\*.cpp) do (
echo formatting %%f
"%VCINSTALLDIR%Tools\Llvm\bin\clang-format" -i --assume-filename x.cpp "%%f"
)

View file

@ -0,0 +1,18 @@
#!/bin/bash
set -euo pipefail
cf=clang-format-$(grep -i 'CLANG_VERSION:' .github/workflows/clang-format.yml | sed -E 's/.*"([^"]+)".*/\1/')
readonly cf
if ! "${cf}" -version; then
echo "[ERROR] clang-format not found. Please install it using: sudo apt install ${cf}"
exit 1
fi
{
find include/gsl -type f
find tests -type f \( -name '*.cpp' -o -name '*.h' \)
} | xargs "${cf}" -i --assume-filename=x.cpp --verbose
find scripts -type f -name '*.sh' -print -exec shfmt -w {} \;

View file

@ -171,8 +171,8 @@ 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 constexpr bool ToIntegerCompilesFor<U, void_t<decltype(gsl::to_integer<U>(gsl::byte{}))>> =
true;
static_assert(!ToIntegerCompilesFor<float>, "!ToIntegerCompilesFor<float>");
} // namespace

View file

@ -59,8 +59,10 @@ constexpr bool workaround_test(const int* ptr1, const int* ptr2)
constexpr int test_value1 = 1;
constexpr int test_value2 = 2;
static_assert(comparison_test(&test_value1, &test_value2), "not_null comparison operators should be constexpr");
static_assert(workaround_test(&test_value1, &test_value2), "not_null .get() comparison workaround should work");
static_assert(comparison_test(&test_value1, &test_value2),
"not_null comparison operators should be constexpr");
static_assert(workaround_test(&test_value1, &test_value2),
"not_null .get() comparison workaround should work");
TEST(notnull_constexpr_tests, TestNotNullConstexprComparison)
{
@ -71,4 +73,3 @@ TEST(notnull_constexpr_tests, TestNotNullConstexprComparison)
EXPECT_TRUE(comparison_test(&value1, &value2));
EXPECT_TRUE(workaround_test(&value1, &value2));
}

View file

@ -69,9 +69,7 @@ struct CustomPtr
template <typename T, typename U>
std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@ -79,9 +77,7 @@ std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U>
std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@ -89,9 +85,7 @@ std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U>
std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@ -99,9 +93,7 @@ std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U>
std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@ -109,9 +101,7 @@ std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U>
std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@ -119,9 +109,7 @@ std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
template <typename T, typename U>
std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
{
// clang-format off
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(type.1)
return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
: "false";
}
@ -137,13 +125,9 @@ struct NonCopyableNonMovable
namespace
{
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.4)
bool helper(not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.4)
bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; }

View file

@ -21,7 +21,7 @@
using namespace gsl;
GSL_SUPPRESS(f.23) // NO-FORMAT: attribute
GSL_SUPPRESS(f.23)
void f(int* i) { *i += 1; }
TEST(owner_tests, basic_test)
@ -43,8 +43,7 @@ using void_t = void;
template <typename U, typename = void>
static constexpr bool OwnerCompilesFor = false;
template <typename U>
static constexpr bool OwnerCompilesFor<U, void_t<decltype(gsl::owner<U>{})>> =
true;
static constexpr bool OwnerCompilesFor<U, void_t<decltype(gsl::owner<U>{})>> = true;
static_assert(OwnerCompilesFor<int*>, "OwnerCompilesFor<int*>");
static_assert(!OwnerCompilesFor<int>, "!OwnerCompilesFor<int>");
static_assert(!OwnerCompilesFor<std::shared_ptr<int>>, "!OwnerCompilesFor<std::shared_ptr<int>>");

View file

@ -44,7 +44,8 @@ TEST(pointers_test, swap)
gsl::not_null<std::unique_ptr<int>> a(std::make_unique<int>(0));
gsl::not_null<std::unique_ptr<int>> b(std::make_unique<int>(1));
static_assert(noexcept(gsl::swap(a, b)), "not null unique_ptr should be noexcept-swappable");
static_assert(noexcept(gsl::swap(a, b)),
"not null unique_ptr should be noexcept-swappable");
EXPECT_TRUE(*a == 0);
EXPECT_TRUE(*b == 1);
@ -65,7 +66,8 @@ TEST(pointers_test, swap)
gsl::strict_not_null<std::unique_ptr<int>> a{std::make_unique<int>(0)};
gsl::strict_not_null<std::unique_ptr<int>> b{std::make_unique<int>(1)};
static_assert(noexcept(gsl::swap(a, b)), "strict not null unique_ptr should be noexcept-swappable");
static_assert(noexcept(gsl::swap(a, b)),
"strict not null unique_ptr should be noexcept-swappable");
EXPECT_TRUE(*a == 0);
EXPECT_TRUE(*b == 1);

View file

@ -61,8 +61,8 @@ void ArrayConvertibilityCheck()
static_assert(std::is_same<decltype(gsl::span{stl_nullptr}), gsl::span<T*, 3>>::value,
"std::is_same< decltype(span{stl_nullptr}), span<T*, 3>>::value");
static_assert(
std::is_same<decltype(gsl::span{std::as_const(stl_nullptr)}), gsl::span<T* const, 3>>::value,
static_assert(std::is_same<decltype(gsl::span{std::as_const(stl_nullptr)}),
gsl::span<T* const, 3>>::value,
"std::is_same< decltype(span{std::as_const(stl_nullptr)}), span<T* const, "
"3>>::value");
}

View file

@ -257,7 +257,9 @@ TEST(span_test, from_pointer_pointer_construction)
EXPECT_TRUE(s.data() == &arr[0]);
}
//{ // this test succeeds on all platforms, gsl::span is more relaxed than std::span where this would be UB
// this test succeeds on all platforms, gsl::span is more relaxed than std::span where this
// would be UB
//{
// auto workaround_macro = [&]() { span<int> s{&arr[1], &arr[0]}; };
// EXPECT_DEATH(workaround_macro(), expected);
//}

View file

@ -41,24 +41,16 @@ struct RefCounted
namespace
{
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.4)
bool helper(not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.4)
bool helper_const(not_null<const int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.4)
bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
// clang-format off
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
// clang-format on
GSL_SUPPRESS(f.4)
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; }
@ -195,7 +187,6 @@ template <typename U>
static constexpr bool
StrictHelperCompilesFor<U, void_t<decltype(strict_helper(std::declval<U>()))>> = true;
template <typename U, typename = void>
static constexpr bool StrictHelperConstCompilesFor = false;
template <typename U>
@ -203,7 +194,6 @@ static constexpr bool
StrictHelperConstCompilesFor<U, void_t<decltype(strict_helper_const(std::declval<U>()))>> =
true;
template <typename U, typename = void>
static constexpr bool HelperCompilesFor = false;
template <typename U>
@ -219,8 +209,7 @@ TEST(strict_notnull_tests, TestStrictNotNull)
strict_not_null<int*> snn = &x;
#endif
static_assert(!StrictHelperCompilesFor<int*>, "!StrictHelperCompilesFor<int*>");
static_assert(!StrictHelperConstCompilesFor<int*>,
"!StrictHelperCompilesFor<int*>");
static_assert(!StrictHelperConstCompilesFor<int*>, "!StrictHelperCompilesFor<int*>");
const strict_not_null<int*> snn1{&x};

View file

@ -156,8 +156,8 @@ TEST(utils_tests, narrow)
n = -42;
EXPECT_THROW(narrow<unsigned>(n), narrowing_error);
EXPECT_TRUE(
narrow<std::complex<float>>(std::complex<double>(4, 2)) == std::complex<float>(4, 2));
EXPECT_TRUE(narrow<std::complex<float>>(std::complex<double>(4, 2)) ==
std::complex<float>(4, 2));
EXPECT_THROW(narrow<std::complex<float>>(std::complex<double>(4.2)), narrowing_error);
EXPECT_TRUE(narrow<int>(float(1)) == 1);