Upgrade to C++20 (#4239)

* Use explicit this capture required by C++20
* Use C++20 span
* Replace wpi::numbers with std::numbers
* Fix C++20 clang-tidy warning false positive in fmt
* Remove ciso646 include since C++20 removed that header
* Fix global-buffer-overflow asan warnings in ntcore tests
* Add DIOSetProxy constructor to HAL

* Upgrade MSVC compiler to 2022
* Bump native-utils to 2023.2.7 (changes to std=c++20)

Co-authored-by: Peter Johnson <johnson.peter@gmail.com>
This commit is contained in:
Tyler Veness
2022-10-15 16:33:14 -07:00
committed by GitHub
parent 396143004c
commit fbdc810887
355 changed files with 1659 additions and 2918 deletions

View File

@@ -2952,7 +2952,7 @@ class format_string_checker {
basic_string_view<Char> format_str, ErrorHandler eh)
: context_(format_str, num_args, types_, eh),
parse_funcs_{&parse_format_specs<Args, parse_context_type>...},
types_{
types_{ // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
mapped_type_constant<Args,
basic_format_context<Char*, Char>>::value...} {
}

View File

@@ -1384,7 +1384,7 @@ json json::from_cbor(raw_istream& is, const bool strict)
return binary_reader(is).parse_cbor(strict);
}
json json::from_cbor(span<const uint8_t> arr, const bool strict)
json json::from_cbor(std::span<const uint8_t> arr, const bool strict)
{
raw_mem_istream is(arr);
return from_cbor(is, strict);
@@ -1395,7 +1395,7 @@ json json::from_msgpack(raw_istream& is, const bool strict)
return binary_reader(is).parse_msgpack(strict);
}
json json::from_msgpack(span<const uint8_t> arr, const bool strict)
json json::from_msgpack(std::span<const uint8_t> arr, const bool strict)
{
raw_mem_istream is(arr);
return from_msgpack(is, strict);
@@ -1406,7 +1406,7 @@ json json::from_ubjson(raw_istream& is, const bool strict)
return binary_reader(is).parse_ubjson(strict);
}
json json::from_ubjson(span<const uint8_t> arr, const bool strict)
json json::from_ubjson(std::span<const uint8_t> arr, const bool strict)
{
raw_mem_istream is(arr);
return from_ubjson(is, strict);

View File

@@ -813,7 +813,7 @@ void json::binary_writer::write_number(const NumberType n)
std::reverse(vec.begin(), vec.end());
}
o << span{vec.data(), sizeof(NumberType)};
o << std::span{vec.data(), sizeof(NumberType)};
}
template<typename NumberType, typename std::enable_if<
@@ -1004,7 +1004,7 @@ std::vector<uint8_t> json::to_cbor(const json& j)
return result;
}
span<uint8_t> json::to_cbor(const json& j, std::vector<uint8_t>& buf)
std::span<uint8_t> json::to_cbor(const json& j, std::vector<uint8_t>& buf)
{
buf.clear();
raw_uvector_ostream os(buf);
@@ -1012,7 +1012,7 @@ span<uint8_t> json::to_cbor(const json& j, std::vector<uint8_t>& buf)
return os.array();
}
span<uint8_t> json::to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf)
std::span<uint8_t> json::to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf)
{
buf.clear();
raw_usvector_ostream os(buf);
@@ -1033,7 +1033,7 @@ std::vector<uint8_t> json::to_msgpack(const json& j)
return result;
}
span<uint8_t> json::to_msgpack(const json& j, std::vector<uint8_t>& buf)
std::span<uint8_t> json::to_msgpack(const json& j, std::vector<uint8_t>& buf)
{
buf.clear();
raw_uvector_ostream os(buf);
@@ -1041,7 +1041,7 @@ span<uint8_t> json::to_msgpack(const json& j, std::vector<uint8_t>& buf)
return os.array();
}
span<uint8_t> json::to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf)
std::span<uint8_t> json::to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf)
{
buf.clear();
raw_usvector_ostream os(buf);
@@ -1064,7 +1064,7 @@ std::vector<uint8_t> json::to_ubjson(const json& j,
return result;
}
span<uint8_t> json::to_ubjson(const json& j, std::vector<uint8_t>& buf,
std::span<uint8_t> json::to_ubjson(const json& j, std::vector<uint8_t>& buf,
const bool use_size, const bool use_type)
{
buf.clear();
@@ -1073,7 +1073,7 @@ span<uint8_t> json::to_ubjson(const json& j, std::vector<uint8_t>& buf,
return os.array();
}
span<uint8_t> json::to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
std::span<uint8_t> json::to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
const bool use_size, const bool use_type)
{
buf.clear();

View File

@@ -1921,11 +1921,11 @@ json json::parse(std::string_view s,
const parser_callback_t cb,
const bool allow_exceptions)
{
raw_mem_istream is(span<const char>(s.data(), s.size()));
raw_mem_istream is(std::span<const char>(s.data(), s.size()));
return parse(is, cb, allow_exceptions);
}
json json::parse(span<const uint8_t> arr,
json json::parse(std::span<const uint8_t> arr,
const parser_callback_t cb,
const bool allow_exceptions)
{
@@ -1944,11 +1944,11 @@ json json::parse(raw_istream& i,
bool json::accept(std::string_view s)
{
raw_mem_istream is(span<const char>(s.data(), s.size()));
raw_mem_istream is(std::span<const char>(s.data(), s.size()));
return parser(is).accept(true);
}
bool json::accept(span<const uint8_t> arr)
bool json::accept(std::span<const uint8_t> arr)
{
raw_mem_istream is(arr);
return parser(is).accept(true);

View File

@@ -43,7 +43,6 @@ SOFTWARE.
#include <algorithm> // all_of, copy, find, for_each, generate_n, min, reverse, remove, fill, none_of, transform
#include <array> // array
#include <cassert> // assert
#include <ciso646> // and, not, or
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <exception> // exception
@@ -52,6 +51,7 @@ SOFTWARE.
#include <iterator>
#include <limits> // numeric_limits
#include <memory> // allocator, shared_ptr, make_shared, addressof
#include <span>
#include <stdexcept> // runtime_error
#include <string> // string, char_traits, stoi, to_string
#include <string_view>
@@ -61,7 +61,6 @@ SOFTWARE.
#include <vector> // vector
#include "wpi/StringMap.h"
#include "wpi/span.h"
namespace wpi
{
@@ -1126,7 +1125,7 @@ struct external_constructor<value_t::array>
}
template<typename BasicJsonType, typename T>
static void construct(BasicJsonType& j, span<T> arr)
static void construct(BasicJsonType& j, std::span<T> arr)
{
using std::begin;
using std::end;
@@ -7015,7 +7014,7 @@ class json
const parser_callback_t cb = nullptr,
const bool allow_exceptions = true);
static json parse(span<const uint8_t> arr,
static json parse(std::span<const uint8_t> arr,
const parser_callback_t cb = nullptr,
const bool allow_exceptions = true);
@@ -7028,7 +7027,7 @@ class json
static bool accept(std::string_view s);
static bool accept(span<const uint8_t> arr);
static bool accept(std::span<const uint8_t> arr);
static bool accept(raw_istream& i);
@@ -7206,8 +7205,8 @@ class json
@since version 2.0.9
*/
static std::vector<uint8_t> to_cbor(const json& j);
static span<uint8_t> to_cbor(const json& j, std::vector<uint8_t>& buf);
static span<uint8_t> to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf);
static std::span<uint8_t> to_cbor(const json& j, std::vector<uint8_t>& buf);
static std::span<uint8_t> to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf);
static void to_cbor(raw_ostream& os, const json& j);
/*!
@@ -7291,8 +7290,8 @@ class json
@since version 2.0.9
*/
static std::vector<uint8_t> to_msgpack(const json& j);
static span<uint8_t> to_msgpack(const json& j, std::vector<uint8_t>& buf);
static span<uint8_t> to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf);
static std::span<uint8_t> to_msgpack(const json& j, std::vector<uint8_t>& buf);
static std::span<uint8_t> to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf);
static void to_msgpack(raw_ostream& os, const json& j);
/*!
@@ -7378,9 +7377,9 @@ class json
static std::vector<uint8_t> to_ubjson(const json& j,
const bool use_size = false,
const bool use_type = false);
static span<uint8_t> to_ubjson(const json& j, std::vector<uint8_t>& buf,
static std::span<uint8_t> to_ubjson(const json& j, std::vector<uint8_t>& buf,
const bool use_size = false, const bool use_type = false);
static span<uint8_t> to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
static std::span<uint8_t> to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
const bool use_size = false, const bool use_type = false);
static void to_ubjson(raw_ostream& os, const json& j,
const bool use_size = false, const bool use_type = false);
@@ -7484,7 +7483,7 @@ class json
/*!
@copydoc from_cbor(raw_istream&, const bool)
*/
static json from_cbor(span<const uint8_t> arr, const bool strict = true);
static json from_cbor(std::span<const uint8_t> arr, const bool strict = true);
/*!
@brief create a JSON value from an input in MessagePack format
@@ -7565,7 +7564,7 @@ class json
/*!
@copydoc from_msgpack(raw_istream&, const bool)
*/
static json from_msgpack(span<const uint8_t> arr, const bool strict = true);
static json from_msgpack(std::span<const uint8_t> arr, const bool strict = true);
/*!
@brief create a JSON value from an input in UBJSON format
@@ -7623,7 +7622,7 @@ class json
static json from_ubjson(raw_istream& is,
const bool strict = true);
static json from_ubjson(span<const uint8_t> arr, const bool strict = true);
static json from_ubjson(std::span<const uint8_t> arr, const bool strict = true);
/// @}

View File

@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "wpi/span.h"
#include <span>
#include "wpi/ConvertUTF.h"
#include "wpi/SmallVector.h"
#include "wpi/ErrorHandling.h"
@@ -21,7 +21,7 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
char *&ResultPtr, const UTF8 *&ErrorPtr) {
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
ConversionResult result = conversionOK;
// Copy the character span over.
// Copy the character std::span over.
if (WideCharWidth == 1) {
const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.data());
if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.data() + Source.size()))) {
@@ -78,13 +78,13 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
return true;
}
bool hasUTF16ByteOrderMark(span<const char> S) {
bool hasUTF16ByteOrderMark(std::span<const char> S) {
return (S.size() >= 2 &&
((S[0] == '\xff' && S[1] == '\xfe') ||
(S[0] == '\xfe' && S[1] == '\xff')));
}
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
assert(Out.empty());
// Error out on an uneven byte count.
@@ -95,8 +95,8 @@ bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &
if (SrcBytes.empty())
return true;
const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin());
const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end());
const UTF16 *Src = reinterpret_cast<const UTF16 *>(&*SrcBytes.begin());
const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(&*SrcBytes.begin() + SrcBytes.size());
assert((uintptr_t)Src % sizeof(UTF16) == 0);
@@ -135,10 +135,10 @@ bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &
return true;
}
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out)
bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out)
{
return convertUTF16ToUTF8String(
span<const char>(reinterpret_cast<const char *>(Src.data()),
std::span<const char>(reinterpret_cast<const char *>(Src.data()),
Src.size() * sizeof(UTF16)), Out);
}
@@ -225,7 +225,7 @@ bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result
return true;
} else if (sizeof(wchar_t) == 2) {
return convertUTF16ToUTF8String(
span<const UTF16>(reinterpret_cast<const UTF16 *>(Source.data()),
std::span<const UTF16>(reinterpret_cast<const UTF16 *>(Source.data()),
Source.size()),
Result);
} else if (sizeof(wchar_t) == 4) {

View File

@@ -104,8 +104,8 @@ namespace {
template <typename MB>
class MemoryBufferMem : public MB {
public:
explicit MemoryBufferMem(span<const uint8_t> inputData) {
MemoryBuffer::Init(inputData.begin(), inputData.end());
explicit MemoryBufferMem(std::span<const uint8_t> inputData) {
MemoryBuffer::Init(&*inputData.begin(), &*inputData.end());
}
/// Disable sized deallocation for MemoryBufferMem, because it has
@@ -129,7 +129,7 @@ static std::unique_ptr<MB> GetFileAux(std::string_view filename,
uint64_t mapSize, uint64_t offset);
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(
span<const uint8_t> inputData, std::string_view bufferName) {
std::span<const uint8_t> inputData, std::string_view bufferName) {
auto* ret = new (NamedBufferAlloc(bufferName))
MemoryBufferMem<MemoryBuffer>(inputData);
return std::unique_ptr<MemoryBuffer>(ret);
@@ -141,7 +141,7 @@ std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(MemoryBufferRef ref) {
}
static std::unique_ptr<WritableMemoryBuffer> GetMemBufferCopyImpl(
span<const uint8_t> inputData, std::string_view bufferName,
std::span<const uint8_t> inputData, std::string_view bufferName,
std::error_code& ec) {
auto buf =
WritableMemoryBuffer::GetNewUninitMemBuffer(inputData.size(), bufferName);
@@ -154,7 +154,7 @@ static std::unique_ptr<WritableMemoryBuffer> GetMemBufferCopyImpl(
}
std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBufferCopy(
span<const uint8_t> inputData, std::string_view bufferName) {
std::span<const uint8_t> inputData, std::string_view bufferName) {
std::error_code ec;
return GetMemBufferCopyImpl(inputData, bufferName, ec);
}

View File

@@ -89,7 +89,7 @@
#ifndef WPIUTIL_WPI_CONVERTUTF_H
#define WPIUTIL_WPI_CONVERTUTF_H
#include "wpi/span.h"
#include <span>
#include <cstddef>
#include <string>
@@ -259,7 +259,7 @@ inline ConversionResult convertUTF8Sequence(const UTF8 **source,
* Returns true if a blob of text starts with a UTF-16 big or little endian byte
* order mark.
*/
bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
bool hasUTF16ByteOrderMark(std::span<const char> SrcBytes);
/**
* Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
@@ -268,7 +268,7 @@ bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &Out);
bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<char> &Out);
/**
* Converts a UTF16 string into a UTF8 std::string.
@@ -277,7 +277,7 @@ bool convertUTF16ToUTF8String(span<const char> SrcBytes, SmallVectorImpl<char> &
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
bool convertUTF16ToUTF8String(span<const UTF16> Src, SmallVectorImpl<char> &Out);
bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out);
/**
* Converts a UTF-8 string into a UTF-16 string with native endianness.

View File

@@ -21,11 +21,10 @@
#include <cstddef>
#include <memory>
#include <span>
#include <string_view>
#include <system_error>
#include "wpi/span.h"
// Duplicated from fs.h to avoid a dependency
namespace fs {
#if defined(_WIN32)
@@ -61,7 +60,7 @@ class MemoryBuffer {
const uint8_t* end() const { return m_bufferEnd; }
size_t size() const { return m_bufferEnd - m_bufferStart; }
span<const uint8_t> GetBuffer() const { return {begin(), end()}; }
std::span<const uint8_t> GetBuffer() const { return {begin(), end()}; }
/// Return an identifier for this buffer, typically the filename it was read
/// from.
@@ -98,14 +97,14 @@ class MemoryBuffer {
/// Open the specified memory range as a MemoryBuffer.
static std::unique_ptr<MemoryBuffer> GetMemBuffer(
span<const uint8_t> inputData, std::string_view bufferName = "");
std::span<const uint8_t> inputData, std::string_view bufferName = "");
static std::unique_ptr<MemoryBuffer> GetMemBuffer(MemoryBufferRef ref);
/// Open the specified memory range as a MemoryBuffer, copying the contents
/// and taking ownership of it.
static std::unique_ptr<MemoryBuffer> GetMemBufferCopy(
span<const uint8_t> inputData, std::string_view bufferName = "");
std::span<const uint8_t> inputData, std::string_view bufferName = "");
/// Map a subrange of the specified file as a MemoryBuffer.
static std::unique_ptr<MemoryBuffer> GetFileSlice(std::string_view filename,
@@ -145,7 +144,7 @@ class WritableMemoryBuffer : public MemoryBuffer {
// guaranteed to have been initialized with a mutable buffer.
uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
span<uint8_t> GetBuffer() { return {begin(), end()}; }
std::span<uint8_t> GetBuffer() { return {begin(), end()}; }
static std::unique_ptr<WritableMemoryBuffer> GetFile(
std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
@@ -196,7 +195,7 @@ class WriteThroughMemoryBuffer : public MemoryBuffer {
// guaranteed to have been initialized with a mutable buffer.
uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
span<uint8_t> GetBuffer() { return {begin(), end()}; }
std::span<uint8_t> GetBuffer() { return {begin(), end()}; }
static std::unique_ptr<WriteThroughMemoryBuffer> GetFile(
std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
@@ -218,22 +217,22 @@ class WriteThroughMemoryBuffer : public MemoryBuffer {
};
class MemoryBufferRef {
span<const uint8_t> m_buffer;
std::span<const uint8_t> m_buffer;
std::string_view m_id;
public:
MemoryBufferRef() = default;
MemoryBufferRef(MemoryBuffer& buffer) // NOLINT
: m_buffer(buffer.GetBuffer()), m_id(buffer.GetBufferIdentifier()) {}
MemoryBufferRef(span<const uint8_t> buffer, std::string_view id)
MemoryBufferRef(std::span<const uint8_t> buffer, std::string_view id)
: m_buffer(buffer), m_id(id) {}
span<const uint8_t> GetBuffer() const { return m_buffer; }
std::span<const uint8_t> GetBuffer() const { return m_buffer; }
std::string_view GetBufferIdentifier() const { return m_id; }
const uint8_t* begin() const { return m_buffer.begin(); }
const uint8_t* end() const { return m_buffer.end(); }
const uint8_t* begin() const { return &*m_buffer.begin(); }
const uint8_t* end() const { return &*m_buffer.end(); }
size_t size() const { return m_buffer.size(); }
};

View File

@@ -14,7 +14,7 @@
#define WPIUTIL_WPI_RAW_OSTREAM_H
#include "wpi/SmallVector.h"
#include "wpi/span.h"
#include <span>
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -199,7 +199,7 @@ public:
return *this;
}
raw_ostream &operator<<(span<const uint8_t> Arr) {
raw_ostream &operator<<(std::span<const uint8_t> Arr) {
// Inline fast path, particularly for arrays with a known length.
size_t Size = Arr.size();
@@ -675,9 +675,9 @@ public:
void flush() = delete;
/// Return an span for the vector contents.
span<uint8_t> array() { return {OS.data(), OS.size()}; }
span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
/// Return an std::span for the vector contents.
std::span<uint8_t> array() { return {OS.data(), OS.size()}; }
std::span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
};
/// A raw_ostream that writes to a vector. This is a
@@ -709,9 +709,9 @@ public:
void flush() = delete;
/// Return a span for the vector contents.
span<uint8_t> array() { return {OS.data(), OS.size()}; }
span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
/// Return a std::span for the vector contents.
std::span<uint8_t> array() { return {OS.data(), OS.size()}; }
std::span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
};

View File

@@ -1,415 +0,0 @@
/*
This is an implementation of C++20's std::span
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf
*/
// Copyright Tristan Brindle 2018.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file ../../LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
#ifndef WPIUTIL_WPI_SPAN_HPP_INCLUDED
#define WPIUTIL_WPI_SPAN_HPP_INCLUDED
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <type_traits>
#if __cplusplus >= 202002L && __has_include(<span>)
#include <span>
#endif
namespace wpi {
inline constexpr std::size_t dynamic_extent = SIZE_MAX;
template <typename ElementType, std::size_t Extent = dynamic_extent>
class span;
namespace detail {
template <typename E, std::size_t S>
struct span_storage {
constexpr span_storage() noexcept = default;
constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept
: ptr(p_ptr)
{}
E* ptr = nullptr;
static constexpr std::size_t size = S;
};
template <typename E>
struct span_storage<E, dynamic_extent> {
constexpr span_storage() noexcept = default;
constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept
: ptr(p_ptr), size(p_size)
{}
E* ptr = nullptr;
std::size_t size = 0;
};
template <typename T>
using uncvref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template <typename>
struct is_span : std::false_type {};
template <typename T, std::size_t S>
struct is_span<span<T, S>> : std::true_type {};
template <typename>
struct is_std_array : std::false_type {};
template <typename T, std::size_t N>
struct is_std_array<std::array<T, N>> : std::true_type {};
template <typename, typename = void>
struct has_size_and_data : std::false_type {};
template <typename T>
struct has_size_and_data<T, std::void_t<decltype(std::size(std::declval<T>())),
decltype(std::data(std::declval<T>()))>>
: std::true_type {};
template <typename C, typename U = uncvref_t<C>>
struct is_container {
static constexpr bool value =
!is_span<U>::value && !is_std_array<U>::value &&
!std::is_array<U>::value && has_size_and_data<C>::value;
};
template <typename T>
using remove_pointer_t = typename std::remove_pointer<T>::type;
template <typename, typename, typename = void>
struct is_container_element_type_compatible : std::false_type {};
template <typename T, typename E>
struct is_container_element_type_compatible<
T, E,
typename std::enable_if<
!std::is_same<typename std::remove_cv<decltype(
std::data(std::declval<T>()))>::type,
void>::value>::type>
: std::is_convertible<
remove_pointer_t<decltype(std::data(std::declval<T>()))> (*)[],
E (*)[]> {};
template <typename, typename = size_t>
struct is_complete : std::false_type {};
template <typename T>
struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
} // namespace detail
template <typename ElementType, std::size_t Extent>
class span {
static_assert(std::is_object<ElementType>::value,
"A span's ElementType must be an object type (not a "
"reference type or void)");
static_assert(detail::is_complete<ElementType>::value,
"A span's ElementType must be a complete type (not a forward "
"declaration)");
static_assert(!std::is_abstract<ElementType>::value,
"A span's ElementType cannot be an abstract class type");
using storage_type = detail::span_storage<ElementType, Extent>;
public:
// constants and types
using element_type = ElementType;
using value_type = typename std::remove_cv<ElementType>::type;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = element_type*;
using const_pointer = const element_type*;
using reference = element_type&;
using const_reference = const element_type&;
using iterator = pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
static constexpr size_type extent = Extent;
// [span.cons], span constructors, copy, assignment, and destructor
template <
std::size_t E = Extent,
typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
constexpr span() noexcept
{}
constexpr span(pointer ptr, size_type count)
: storage_(ptr, count)
{
assert(extent == dynamic_extent || count == extent);
}
constexpr span(pointer first_elem, pointer last_elem)
: storage_(first_elem, last_elem - first_elem)
{
assert(extent == dynamic_extent ||
last_elem - first_elem ==
static_cast<std::ptrdiff_t>(extent));
}
template <std::size_t N, std::size_t E = Extent,
typename std::enable_if<
(E == dynamic_extent || N == E) &&
detail::is_container_element_type_compatible<
element_type (&)[N], ElementType>::value,
int>::type = 0>
constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
{}
template <std::size_t N, std::size_t E = Extent,
typename std::enable_if<
(E == dynamic_extent || N == E) &&
detail::is_container_element_type_compatible<
std::array<value_type, N>&, ElementType>::value,
int>::type = 0>
constexpr span(std::array<value_type, N>& arr) noexcept
: storage_(arr.data(), N)
{}
template <std::size_t N, std::size_t E = Extent,
typename std::enable_if<
(E == dynamic_extent || N == E) &&
detail::is_container_element_type_compatible<
const std::array<value_type, N>&, ElementType>::value,
int>::type = 0>
constexpr span(const std::array<value_type, N>& arr) noexcept
: storage_(arr.data(), N)
{}
template <
typename Container, std::size_t E = Extent,
typename std::enable_if<
E == dynamic_extent && detail::is_container<Container>::value &&
detail::is_container_element_type_compatible<
Container&, ElementType>::value,
int>::type = 0>
constexpr span(Container& cont)
: storage_(std::data(cont), std::size(cont))
{}
template <
typename Container, std::size_t E = Extent,
typename std::enable_if<
E == dynamic_extent && detail::is_container<Container>::value &&
detail::is_container_element_type_compatible<
const Container&, ElementType>::value,
int>::type = 0>
constexpr span(const Container& cont)
: storage_(std::data(cont), std::size(cont))
{}
constexpr span(const span& other) noexcept = default;
template <typename OtherElementType, std::size_t OtherExtent,
typename std::enable_if<
(Extent == OtherExtent || Extent == dynamic_extent) &&
std::is_convertible<OtherElementType (*)[],
ElementType (*)[]>::value,
int>::type = 0>
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
: storage_(other.data(), other.size())
{}
#ifdef __cpp_lib_span
constexpr span(std::span<ElementType> other) noexcept
: storage_(other.data(), other.size())
{}
#endif
~span() noexcept = default;
constexpr span&
operator=(const span& other) noexcept = default;
// [span.sub], span subviews
template <std::size_t Count>
constexpr span<element_type, Count> first() const
{
assert(Count <= size());
return {data(), Count};
}
template <std::size_t Count>
constexpr span<element_type, Count> last() const
{
assert(Count <= size());
return {data() + (size() - Count), Count};
}
template <std::size_t Offset, std::size_t Count = dynamic_extent>
using subspan_return_t =
span<ElementType, Count != dynamic_extent
? Count
: (Extent != dynamic_extent ? Extent - Offset
: dynamic_extent)>;
template <std::size_t Offset, std::size_t Count = dynamic_extent>
constexpr subspan_return_t<Offset, Count> subspan() const
{
assert(Offset <= size() &&
(Count == dynamic_extent || Offset + Count <= size()));
return {data() + Offset,
Count != dynamic_extent ? Count : size() - Offset};
}
constexpr span<element_type, dynamic_extent>
first(size_type count) const
{
assert(count <= size());
return {data(), count};
}
constexpr span<element_type, dynamic_extent>
last(size_type count) const
{
assert(count <= size());
return {data() + (size() - count), count};
}
constexpr span<element_type, dynamic_extent>
subspan(size_type offset, size_type count = dynamic_extent) const
{
assert(offset <= size() &&
(count == dynamic_extent || offset + count <= size()));
return {data() + offset,
count == dynamic_extent ? size() - offset : count};
}
// [span.obs], span observers
constexpr size_type size() const noexcept { return storage_.size; }
constexpr size_type size_bytes() const noexcept
{
return size() * sizeof(element_type);
}
[[nodiscard]] constexpr bool empty() const noexcept
{
return size() == 0;
}
// [span.elem], span element access
constexpr reference operator[](size_type idx) const
{
assert(idx < size());
return *(data() + idx);
}
constexpr reference front() const
{
assert(!empty());
return *data();
}
constexpr reference back() const
{
assert(!empty());
return *(data() + (size() - 1));
}
constexpr pointer data() const noexcept { return storage_.ptr; }
// [span.iterators], span iterator support
constexpr iterator begin() const noexcept { return data(); }
constexpr iterator end() const noexcept { return data() + size(); }
constexpr reverse_iterator rbegin() const noexcept
{
return reverse_iterator(end());
}
constexpr reverse_iterator rend() const noexcept
{
return reverse_iterator(begin());
}
#ifdef __cpp_lib_span
constexpr operator auto() const {
return std::span < ElementType,
(Extent == dynamic_extent)
? std::dynamic_extent
: Extent > (storage_.ptr, storage_.size);
}
#endif
private:
storage_type storage_{};
};
/* Deduction Guides */
template <class T, size_t N>
span(T (&)[N])->span<T, N>;
template <class T, size_t N>
span(std::array<T, N>&)->span<T, N>;
template <class T, size_t N>
span(const std::array<T, N>&)->span<const T, N>;
template <class Container>
span(Container&)->span<typename Container::value_type>;
template <class Container>
span(const Container&)->span<const typename Container::value_type>;
template <typename ElementType, std::size_t Extent>
span<const std::byte, ((Extent == dynamic_extent) ? dynamic_extent
: sizeof(ElementType) * Extent)>
as_bytes(span<ElementType, Extent> s) noexcept
{
return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
}
template <
class ElementType, size_t Extent,
typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
span<std::byte, ((Extent == dynamic_extent) ? dynamic_extent
: sizeof(ElementType) * Extent)>
as_writable_bytes(span<ElementType, Extent> s) noexcept
{
return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
}
template <std::size_t N, typename E, std::size_t S>
constexpr auto get(span<E, S> s) -> decltype(s[N])
{
return s[N];
}
} // namespace wpi
namespace std {
template <typename ElementType, size_t Extent>
class tuple_size<wpi::span<ElementType, Extent>>
: public integral_constant<size_t, Extent> {};
template <typename ElementType>
class tuple_size<wpi::span<
ElementType, wpi::dynamic_extent>>; // not defined
template <size_t I, typename ElementType, size_t Extent>
class tuple_element<I, wpi::span<ElementType, Extent>> {
public:
static_assert(Extent != wpi::dynamic_extent &&
I < Extent,
"");
using type = ElementType;
};
} // end namespace std
#endif // WPIUTIL_WPI_SPAN_HPP_INCLUDED