blob: eac7c3a4053abbc328df5f2104c034797c106661 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_ABI_SPAN_H_
#define SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_ABI_SPAN_H_
#include "internal/abi-span.h"
namespace elfldltl {
// elfldltl::AbiSpan<T> is like a C++20 std::span<T> but with the same
// properties as elfldltl::AbiPtr<T> (see <lib/elfldltl/abi-ptr.h>): it can be
// used to store pointers and lengths that use a different byte order, address
// size, or address space, than the current process.
//
// It always supports the std::span constructors and operations that don't use
// take T* pointers or dereference into the span (size, subspan, etc.), but
// not the iterator methods (begin, end, etc.).
//
// When instantiated for the native byte order, address size, and address
// space, it supports all the other std::span<T> methods (though not all the
// fancy constructors), can be copy-constructed from std::span<T>, and also has
// an explicit `get()` method to return it. The iterator methods (begin, end,
// etc.) return the std::span<T> iterator types directly.
template <typename T, size_t N = cpp20::dynamic_extent, class Elf = elfldltl::Elf<>,
class Traits = LocalAbiTraits>
class AbiSpan : public internal::AbiSpanImpl<T, N, Elf, Traits> {
public:
using typename internal::AbiSpanImpl<T, N, Elf, Traits>::Ptr;
using typename internal::AbiSpanImpl<T, N, Elf, Traits>::size_type;
constexpr AbiSpan() = default;
constexpr AbiSpan(const AbiSpan&) = default;
constexpr AbiSpan(Ptr ptr, size_type size) noexcept
: internal::AbiSpanImpl<T, N, Elf, Traits>(ptr) {
assert(size == N);
}
// If T is const, then non-const pointers are OK too.
template <typename TT = T, typename = std::enable_if_t<std::is_const_v<TT>>>
constexpr AbiSpan(AbiPtr<std::remove_const_t<T>, Elf, Traits> ptr, size_type size) noexcept
: AbiSpan{Ptr{ptr}, size} {}
// Allow copy-construction from the corresponding span type if it admits
// construction from a pointer. Note that span's "range" copy-constructor
// already allows the other direction because AbiSpan has data() and size().
template <typename P = T*, typename = std::enable_if_t<std::is_constructible_v<Ptr, P>>>
constexpr AbiSpan(cpp20::span<T, N> other)
: internal::AbiSpanImpl<T, N, Elf, Traits>(Ptr{other.data()}) {}
// This is redundant with the cpp20::span<T, N> overloads below if they're
// available, because a non-const cpp20::span will implicitly convert.
template <typename TT,
typename = std::enable_if_t<std::is_const_v<TT> && std::is_constructible_v<Ptr, TT*>>>
constexpr AbiSpan& operator=(const AbiSpan<std::remove_const_t<T>, N, Elf, Traits>& other) {
*this = AbiSpan{other.ptr(), other.size()};
return *this;
}
template <typename TT = T, typename = std::enable_if_t<std::is_constructible_v<Ptr, TT*>>>
constexpr AbiSpan& operator=(cpp20::span<T, N> other) {
*this = AbiSpan{other};
return *this;
}
constexpr size_type size() const { return static_cast<size_type>(N); }
};
template <typename T, class Elf, class Traits>
class AbiSpan<T, cpp20::dynamic_extent, Elf, Traits>
: public internal::AbiSpanImpl<T, cpp20::dynamic_extent, Elf, Traits> {
public:
using typename internal::AbiSpanImpl<T, cpp20::dynamic_extent, Elf, Traits>::Ptr;
using typename internal::AbiSpanImpl<T, cpp20::dynamic_extent, Elf, Traits>::Addr;
using typename internal::AbiSpanImpl<T, cpp20::dynamic_extent, Elf, Traits>::size_type;
constexpr AbiSpan() = default;
constexpr AbiSpan(const AbiSpan&) = default;
constexpr AbiSpan(Ptr ptr, size_type size) noexcept
: internal::AbiSpanImpl<T, cpp20::dynamic_extent, Elf, Traits>{ptr}, size_(size) {}
template <typename TT, typename = std::enable_if_t<std::is_const_v<TT>>>
constexpr AbiSpan(AbiPtr<std::remove_const_t<T>, Elf, Traits> ptr, size_type size) noexcept
: AbiSpan{Ptr{ptr}, size} {}
// See comment above.
template <typename TT = T, typename = std::enable_if_t<std::is_constructible_v<Ptr, TT*>>>
constexpr AbiSpan(cpp20::span<T> other)
: internal::AbiSpanImpl<T, cpp20::dynamic_extent, Elf, Traits>{Ptr{other.data()}},
size_{static_cast<size_type>(other.size())} {}
constexpr AbiSpan& operator=(const AbiSpan&) = default;
// This is redundant with the cpp20::span<T> overload below if available.
template <typename TT = T,
typename = std::enable_if_t<std::is_const_v<TT> && !std::is_constructible_v<Ptr, TT*>>>
constexpr AbiSpan& operator=(
const AbiSpan<std::remove_const_t<T>, cpp20::dynamic_extent, Elf, Traits>& other) {
*this = AbiSpan{other.ptr(), other.size()};
return *this;
}
template <typename TT = T, typename = std::enable_if_t<std::is_constructible_v<Ptr, TT*>>>
constexpr AbiSpan& operator=(cpp20::span<T> other) {
*this = AbiSpan{other};
return *this;
}
constexpr size_type size() const { return size_; }
private:
Addr size_ = 0;
};
// elfldltl::AbiStringView stands in for std::string_view, but is actually
// based on elfldltl::AbiSpan<const char>.
//
// It only replicates the most basic methods of std::string_view. When
// dereferencing is supported by the Traits type, it just provides a `get()`
// method and implicit conversion to and from std::string_view so it can be
// copied into a std::string_view to call the various methods.
template <class Elf = elfldltl::Elf<>, class Traits = LocalAbiTraits>
class AbiStringView {
public:
using Span = AbiSpan<const char, cpp20::dynamic_extent, Elf, Traits>;
using Ptr = typename Span::Ptr;
using size_type = typename Span::size_type;
constexpr AbiStringView() = default;
constexpr AbiStringView(const AbiStringView&) = default;
constexpr explicit AbiStringView(Span contents) : contents_(contents) {}
constexpr AbiStringView(Ptr ptr, size_type length) : contents_{ptr, length} {}
template <typename S = Span,
typename = std::enable_if_t<std::is_constructible_v<S, cpp20::span<const char>>>>
constexpr AbiStringView(std::string_view str) : contents_{cpp20::span{str}} {}
constexpr AbiStringView& operator=(const AbiStringView&) = default;
constexpr bool empty() const { return contents_.empty(); }
constexpr size_t size() const { return contents_.size(); }
constexpr size_t length() const { return contents_.size(); }
constexpr typename Span::Ptr ptr() const { return contents_.ptr(); }
constexpr Span as_span() const { return contents_; }
template <typename S = Span, typename = decltype(S{}.get())>
constexpr operator std::string_view() const {
return get();
}
template <typename S = Span, typename = decltype(S{}.data())>
constexpr std::string_view get() const {
return {data(), size()};
}
template <typename S = Span, typename = decltype(S{}.data())>
constexpr const char* data() const {
return contents_.data();
}
private:
Span contents_;
};
} // namespace elfldltl
#endif // SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_ABI_SPAN_H_