From 2b57891e076b770361a1d6e1745e2fd7151c4ba4 Mon Sep 17 00:00:00 2001 From: asynts Date: Mon, 27 Jul 2020 13:51:12 +0200 Subject: [PATCH] AK: Add constructors to Bytes and ReadonlyBytes that take void pointers. --- AK/Span.h | 204 +++++++++++++++++++++++++++++----------------- AK/Tests/Span.cpp | 13 +++ 2 files changed, 143 insertions(+), 74 deletions(-) diff --git a/AK/Span.h b/AK/Span.h index e974ce8807..4a856fe83c 100644 --- a/AK/Span.h +++ b/AK/Span.h @@ -32,87 +32,17 @@ namespace AK { +namespace Detail { + template class Span { public: - using Iterator = T*; - using ConstIterator = const T*; - - static_assert(!IsPointer::value); - ALWAYS_INLINE Span() = default; + ALWAYS_INLINE Span(T* values, size_t size) : m_values(values) , m_size(size) { - ASSERT(!Checked::addition_would_overflow((uintptr_t)values, size * sizeof(T))); - } - ALWAYS_INLINE Span(const Span& other) - : m_values(other.m_values) - , m_size(other.m_size) - { - } - - ALWAYS_INLINE const T* data() const { return m_values; } - ALWAYS_INLINE T* data() { return m_values; } - - ALWAYS_INLINE ConstIterator begin() const - { - return m_values; - } - ALWAYS_INLINE ConstIterator end() const - { - return begin() + m_size; - } - - ALWAYS_INLINE Iterator begin() - { - return m_values; - } - ALWAYS_INLINE Iterator end() - { - return begin() + m_size; - } - - ALWAYS_INLINE size_t size() const { return m_size; } - - ALWAYS_INLINE bool is_empty() const { return m_size == 0; } - - ALWAYS_INLINE Span subspan(size_t start, size_t size) const - { - ASSERT(start + size <= m_size); - return { m_values + start, size }; - } - - ALWAYS_INLINE const T& at(size_t index) const - { - ASSERT(index < m_size); - return m_values[index]; - } - ALWAYS_INLINE T& at(size_t index) - { - ASSERT(index < m_size); - return m_values[index]; - } - - ALWAYS_INLINE T& operator[](size_t index) const - { - return m_values[index]; - } - ALWAYS_INLINE T& operator[](size_t index) - { - return m_values[index]; - } - - ALWAYS_INLINE T& operator=(const T& other) - { - m_size = other.m_size; - m_values = other.m_values; - } - - ALWAYS_INLINE operator Span() const - { - return { data(), size() }; } protected: @@ -120,9 +50,135 @@ protected: size_t m_size { 0 }; }; +template<> +class Span { +public: + ALWAYS_INLINE Span() = default; + + ALWAYS_INLINE Span(u8* values, size_t size) + : m_values(values) + , m_size(size) + { + } + ALWAYS_INLINE Span(void* values, size_t size) + : m_values(reinterpret_cast(values)) + , m_size(size) + { + } + +protected: + u8* m_values { nullptr }; + size_t m_size { 0 }; +}; + +template<> +class Span { +public: + ALWAYS_INLINE Span() = default; + + ALWAYS_INLINE Span(const u8* values, size_t size) + : m_values(values) + , m_size(size) + { + } + ALWAYS_INLINE Span(const void* values, size_t size) + : m_values(reinterpret_cast(values)) + , m_size(size) + { + } + ALWAYS_INLINE Span(const char* values, size_t size) + : m_values(reinterpret_cast(values)) + , m_size(size) + { + } + +protected: + const u8* m_values { nullptr }; + size_t m_size { 0 }; +}; + +} + +template +class Span : public Detail::Span { +public: + using Iterator = T*; + using ConstIterator = const T*; + + static_assert(!IsPointer::value); + + using Detail::Span::Span; + + ALWAYS_INLINE Span(const Span& other) + : Span(other.m_values, other.m_size) + { + } + + ALWAYS_INLINE const T* data() const { return this->m_values; } + ALWAYS_INLINE T* data() { return this->m_values; } + + ALWAYS_INLINE ConstIterator begin() const + { + return this->m_values; + } + ALWAYS_INLINE ConstIterator end() const + { + return begin() + size(); + } + + ALWAYS_INLINE Iterator begin() + { + return this->m_values; + } + ALWAYS_INLINE Iterator end() + { + return begin() + size(); + } + + ALWAYS_INLINE size_t size() const { return this->m_size; } + + ALWAYS_INLINE bool is_empty() const { return this->m_size == 0; } + + ALWAYS_INLINE Span subspan(size_t start, size_t size) const + { + ASSERT(start + size <= this->m_size); + return { this->m_values + start, size }; + } + + ALWAYS_INLINE const T& at(size_t index) const + { + ASSERT(index < this->m_size); + return this->m_values[index]; + } + ALWAYS_INLINE T& at(size_t index) + { + ASSERT(index < this->m_size); + return this->m_values[index]; + } + + ALWAYS_INLINE T& operator[](size_t index) const + { + return this->m_values[index]; + } + ALWAYS_INLINE T& operator[](size_t index) + { + return this->m_values[index]; + } + + ALWAYS_INLINE T& operator=(const T& other) + { + this->m_size = other.m_size; + this->m_values = other.m_values; + } + + ALWAYS_INLINE operator Span() const + { + return { data(), size() }; + } +}; + using ReadonlyBytes = Span; using Bytes = Span; - } using AK::Bytes; diff --git a/AK/Tests/Span.cpp b/AK/Tests/Span.cpp index 301a1f9c28..1eb0dd68de 100644 --- a/AK/Tests/Span.cpp +++ b/AK/Tests/Span.cpp @@ -131,4 +131,17 @@ TEST_CASE(can_subspan_as_intended) EXPECT_EQ(subspan[1], 5); } +TEST_CASE(span_from_void_pointer) +{ + int value = 0; + [[maybe_unused]] Bytes bytes0 { reinterpret_cast(value), 4 }; + [[maybe_unused]] ReadonlyBytes bytes1 { reinterpret_cast(value), 4 }; +} + +TEST_CASE(span_from_c_string) +{ + const char* str = "Serenity"; + [[maybe_unused]] ReadonlyBytes bytes { str, strlen(str) }; +} + TEST_MAIN(Span)