// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iterator>
#include <type_traits>
namespace arrow::util {
template <class T>
class span;
/// std::span polyfill.
///
/// Does not support static extents.
template <typename T>
class span {
static_assert(sizeof(T),
R"(
std::span allows contiguous_iterators instead of just pointers, the enforcement
of which requires T to be a complete type. arrow::util::span does not support
contiguous_iterators, but T is still required to be a complete type to prevent
writing code which would break when it is replaced by std::span.)");
public:
using element_type = T;
using value_type = std::remove_cv_t<T>;
using iterator = T*;
using const_iterator = T const*;
span() = default;
span(const span&) = default;
span& operator=(const span&) = default;
template <typename M, typename = std::enable_if_t<std::is_same_v<T, M const>>>
// NOLINTNEXTLINE runtime/explicit
constexpr span(span<M> mut) : span{mut.data(), mut.size()} {}
constexpr span(T* data, size_t count) : data_{data}, size_{count} {}
constexpr span(T* begin, T* end)
: data_{begin}, size_{static_cast<size_t>(end - begin)} {}
template <typename R, typename RD = decltype(std::data(std::declval<R>())),
typename RS = decltype(std::size(std::declval<R>())),
typename E = std::enable_if_t<std::is_constructible_v<T*, RD> &&
std::is_constructible_v<size_t, RS>>>
// NOLINTNEXTLINE runtime/explicit, non-const reference
constexpr span(R&& range) : data_{std::data(range)}, size_{std::size(range)} {}
constexpr T* begin() const { return data_; }
constexpr T* end() const { return data_ + size_; }
constexpr T* data() const { return data_; }
constexpr size_t size() const { return size_; }
constexpr size_t size_bytes() const { return size_ * sizeof(T); }
constexpr bool empty() const { return size_ == 0; }
constexpr T& operator[](size_t i) { return data_[i]; }
constexpr const T& operator[](size_t i) const { return data_[i]; }
constexpr span subspan(size_t offset) const {
if (offset > size_) return {data_, data_};
return {data_ + offset, size_ - offset};
}
constexpr span subspan(size_t offset, size_t count) const {
auto out = subspan(offset);
if (count < out.size_) {
out.size_ = count;
}
return out;
}
constexpr bool operator==(span const& other) const {
if (size_ != other.size_) return false;
if constexpr (std::is_integral_v<T>) {
if (size_ == 0) {
return true; // memcmp does not handle null pointers, even if size_ == 0
}
return std::memcmp(data_, other.data_, size_bytes()) == 0;
} else {
T* ptr = data_;
for (T const& e : other) {
if (*ptr++ != e) return false;
}
return true;
}
}
constexpr bool operator!=(span const& other) const { return !(*this == other); }
private:
T* data_{};
size_t size_{};
};
template <typename R>
span(R& range) -> span<std::remove_pointer_t<decltype(std::data(range))>>;
template <typename T>
span(T*, size_t) -> span<T>;
template <typename T>
constexpr span<std::byte const> as_bytes(span<T> s) {
return {reinterpret_cast<std::byte const*>(s.data()), s.size_bytes()};
}
template <typename T>
constexpr span<std::byte> as_writable_bytes(span<T> s) {
return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
}
} // namespace arrow::util