132 lines
4.2 KiB
C++
132 lines
4.2 KiB
C++
// 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
|