libcamera: Add a C++20-compliant std::span<> implementation
C++20 will contain a std::span<> class that provides view over a contiguous sequence of objects, the storage of which is owned by some other object. Add a compatible implementation to the utils namespace. This will be used to implement array controls. Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
dd9429f438
commit
09ab21b85a
3 changed files with 420 additions and 1 deletions
|
@ -840,7 +840,8 @@ RECURSIVE = YES
|
|||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = @TOP_SRCDIR@/src/libcamera/device_enumerator_sysfs.cpp \
|
||||
EXCLUDE = @TOP_SRCDIR@/include/libcamera/span.h \
|
||||
@TOP_SRCDIR@/src/libcamera/device_enumerator_sysfs.cpp \
|
||||
@TOP_SRCDIR@/src/libcamera/device_enumerator_udev.cpp \
|
||||
@TOP_SRCDIR@/src/libcamera/include/device_enumerator_sysfs.h \
|
||||
@TOP_SRCDIR@/src/libcamera/include/device_enumerator_udev.h \
|
||||
|
|
|
@ -14,6 +14,7 @@ libcamera_api = files([
|
|||
'pixelformats.h',
|
||||
'request.h',
|
||||
'signal.h',
|
||||
'span.h',
|
||||
'stream.h',
|
||||
'timer.h',
|
||||
])
|
||||
|
|
417
include/libcamera/span.h
Normal file
417
include/libcamera/span.h
Normal file
|
@ -0,0 +1,417 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020, Google Inc.
|
||||
*
|
||||
* span.h - C++20 std::span<> implementation for C++11
|
||||
*/
|
||||
|
||||
#ifndef __LIBCAMERA_SPAN_H__
|
||||
#define __LIBCAMERA_SPAN_H__
|
||||
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stddef.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
static constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
template<typename T, std::size_t Extent = dynamic_extent>
|
||||
class Span;
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename U>
|
||||
struct is_array : public std::false_type {
|
||||
};
|
||||
|
||||
template<typename U, std::size_t N>
|
||||
struct is_array<std::array<U, N>> : public std::true_type {
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
struct is_span : public std::false_type {
|
||||
};
|
||||
|
||||
template<typename U, std::size_t Extent>
|
||||
struct is_span<Span<U, Extent>> : public std::true_type {
|
||||
};
|
||||
|
||||
} /* namespace details */
|
||||
|
||||
namespace utils {
|
||||
|
||||
template<typename C>
|
||||
constexpr auto size(const C &c) -> decltype(c.size())
|
||||
{
|
||||
return c.size();
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
constexpr auto data(const C &c) -> decltype(c.data())
|
||||
{
|
||||
return c.data();
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
constexpr auto data(C &c) -> decltype(c.data())
|
||||
{
|
||||
return c.data();
|
||||
}
|
||||
|
||||
template<class T, std::size_t N>
|
||||
constexpr T *data(T (&array)[N]) noexcept
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
template<std::size_t I, typename T>
|
||||
struct tuple_element;
|
||||
|
||||
template<std::size_t I, typename T, std::size_t N>
|
||||
struct tuple_element<I, Span<T, N>> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct tuple_size;
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
struct tuple_size<Span<T, N>> : public std::integral_constant<std::size_t, N> {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct tuple_size<Span<T, dynamic_extent>>;
|
||||
|
||||
} /* namespace utils */
|
||||
|
||||
template<typename T, std::size_t Extent>
|
||||
class Span
|
||||
{
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = typename std::remove_cv_t<T>;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr std::size_t extent = Extent;
|
||||
|
||||
template<bool Dependent = false,
|
||||
typename = std::enable_if_t<Dependent || Extent == 0>>
|
||||
constexpr Span() noexcept
|
||||
: data_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Span(pointer ptr, size_type count)
|
||||
: data_(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Span(pointer first, pointer last)
|
||||
: data_(first)
|
||||
{
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr Span(element_type (&arr)[N],
|
||||
std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
|
||||
element_type (*)[]>::value &&
|
||||
N == Extent,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(arr)
|
||||
{
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr Span(std::array<value_type, N> &arr,
|
||||
std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
|
||||
element_type (*)[]>::value &&
|
||||
N == Extent,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(arr.data())
|
||||
{
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr Span(const std::array<value_type, N> &arr,
|
||||
std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
|
||||
element_type (*)[]>::value &&
|
||||
N == Extent,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(arr.data())
|
||||
{
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
constexpr Span(Container &cont,
|
||||
std::enable_if_t<!details::is_span<Container>::value &&
|
||||
!details::is_array<Container>::value &&
|
||||
!std::is_array<Container>::value &&
|
||||
std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr)
|
||||
: data_(utils::data(cont))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
constexpr Span(const Container &cont,
|
||||
std::enable_if_t<!details::is_span<Container>::value &&
|
||||
!details::is_array<Container>::value &&
|
||||
!std::is_array<Container>::value &&
|
||||
std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr)
|
||||
: data_(utils::data(cont))
|
||||
{
|
||||
static_assert(utils::size(cont) == Extent, "Size mismatch");
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
constexpr Span(const Span<U, N> &s,
|
||||
std::enable_if_t<std::is_convertible<U (*)[], element_type (*)[]>::value &&
|
||||
N == Extent,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(s.data())
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Span(const Span &other) noexcept = default;
|
||||
|
||||
constexpr Span &operator=(const Span &other) noexcept
|
||||
{
|
||||
data_ = other.data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr iterator begin() const { return data(); }
|
||||
constexpr const_iterator cbegin() const { return begin(); }
|
||||
constexpr iterator end() const { return data() + size(); }
|
||||
constexpr const_iterator cend() const { return end(); }
|
||||
constexpr reverse_iterator rbegin() const { return reverse_iterator(data() + size() - 1); }
|
||||
constexpr const_reverse_iterator crbegin() const { return rbegin(); }
|
||||
constexpr reverse_iterator rend() const { return reverse_iterator(data() - 1); }
|
||||
constexpr const_reverse_iterator crend() const { return rend(); }
|
||||
|
||||
constexpr reference front() const { return *data(); }
|
||||
constexpr reference back() const { return *(data() + size() - 1); }
|
||||
constexpr reference operator[](size_type idx) const { return data()[idx]; }
|
||||
constexpr pointer data() const noexcept { return data_; }
|
||||
|
||||
constexpr size_type size() const noexcept { return Extent; }
|
||||
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
template<std::size_t Count>
|
||||
constexpr Span<element_type, Count> first() const
|
||||
{
|
||||
static_assert(Count <= Extent, "Count larger than size");
|
||||
return { data(), Count };
|
||||
}
|
||||
|
||||
constexpr Span<element_type, dynamic_extent> first(std::size_t Count) const
|
||||
{
|
||||
return { data(), Count };
|
||||
}
|
||||
|
||||
template<std::size_t Count>
|
||||
constexpr Span<element_type, Count> last() const
|
||||
{
|
||||
static_assert(Count <= Extent, "Count larger than size");
|
||||
return { data() + size() - Count, Count };
|
||||
}
|
||||
|
||||
constexpr Span<element_type, dynamic_extent> last(std::size_t Count) const
|
||||
{
|
||||
return { data() + size() - Count, Count };
|
||||
}
|
||||
|
||||
template<std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
constexpr Span<element_type, Count != dynamic_extent ? Count : Extent - Offset> subspan() const
|
||||
{
|
||||
static_assert(Offset <= Extent, "Offset larger than size");
|
||||
static_assert(Count == dynamic_extent || Count + Offset <= Extent,
|
||||
"Offset + Count larger than size");
|
||||
return { data() + Offset, Count == dynamic_extent ? size() - Offset : Count };
|
||||
}
|
||||
|
||||
constexpr Span<element_type, dynamic_extent>
|
||||
subspan(std::size_t Offset, std::size_t Count = dynamic_extent) const
|
||||
{
|
||||
return { data() + Offset, Count == dynamic_extent ? size() - Offset : Count };
|
||||
}
|
||||
|
||||
private:
|
||||
pointer data_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Span<T, dynamic_extent>
|
||||
{
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = typename std::remove_cv_t<T>;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
using iterator = T *;
|
||||
using const_iterator = const T *;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr std::size_t extent = dynamic_extent;
|
||||
|
||||
constexpr Span() noexcept
|
||||
: data_(nullptr), size_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Span(pointer ptr, size_type count)
|
||||
: data_(ptr), size_(count)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Span(pointer first, pointer last)
|
||||
: data_(first), size_(last - first)
|
||||
{
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr Span(element_type (&arr)[N],
|
||||
std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(arr), size_(N)
|
||||
{
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr Span(std::array<value_type, N> &arr,
|
||||
std::enable_if_t<std::is_convertible<std::remove_pointer_t<decltype(utils::data(arr))> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(utils::data(arr)), size_(N)
|
||||
{
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
constexpr Span(const std::array<value_type, N> &arr) noexcept
|
||||
: data_(utils::data(arr)), size_(N)
|
||||
{
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
constexpr Span(Container &cont,
|
||||
std::enable_if_t<!details::is_span<Container>::value &&
|
||||
!details::is_array<Container>::value &&
|
||||
!std::is_array<Container>::value &&
|
||||
std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr)
|
||||
: data_(utils::data(cont)), size_(utils::size(cont))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
constexpr Span(const Container &cont,
|
||||
std::enable_if_t<!details::is_span<Container>::value &&
|
||||
!details::is_array<Container>::value &&
|
||||
!std::is_array<Container>::value &&
|
||||
std::is_convertible<std::remove_pointer_t<decltype(utils::data(cont))> (*)[],
|
||||
element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr)
|
||||
: data_(utils::data(cont)), size_(utils::size(cont))
|
||||
{
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
constexpr Span(const Span<U, N> &s,
|
||||
std::enable_if_t<std::is_convertible<U (*)[], element_type (*)[]>::value,
|
||||
std::nullptr_t> = nullptr) noexcept
|
||||
: data_(s.data()), size_(s.size())
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Span(const Span &other) noexcept = default;
|
||||
|
||||
constexpr Span &operator=(const Span &other) noexcept
|
||||
{
|
||||
data_ = other.data_;
|
||||
size_ = other.size_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr iterator begin() const { return data(); }
|
||||
constexpr const_iterator cbegin() const { return begin(); }
|
||||
constexpr iterator end() const { return data() + size(); }
|
||||
constexpr const_iterator cend() const { return end(); }
|
||||
constexpr reverse_iterator rbegin() const { return reverse_iterator(data() + size() - 1); }
|
||||
constexpr const_reverse_iterator crbegin() const { return rbegin(); }
|
||||
constexpr reverse_iterator rend() const { return reverse_iterator(data() - 1); }
|
||||
constexpr const_reverse_iterator crend() const { return rend(); }
|
||||
|
||||
constexpr reference front() const { return *data(); }
|
||||
constexpr reference back() const { return *(data() + size() - 1); }
|
||||
constexpr reference operator[](size_type idx) const { return data()[idx]; }
|
||||
constexpr pointer data() const noexcept { return data_; }
|
||||
|
||||
constexpr size_type size() const noexcept { return size_; }
|
||||
constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
|
||||
constexpr bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
template<std::size_t Count>
|
||||
constexpr Span<element_type, Count> first() const
|
||||
{
|
||||
return { data(), Count };
|
||||
}
|
||||
|
||||
constexpr Span<element_type, dynamic_extent> first(std::size_t Count) const
|
||||
{
|
||||
return { data(), Count };
|
||||
}
|
||||
|
||||
template<std::size_t Count>
|
||||
constexpr Span<element_type, Count> last() const
|
||||
{
|
||||
return { data() + size() - Count, Count };
|
||||
}
|
||||
|
||||
constexpr Span<element_type, dynamic_extent> last(std::size_t Count) const
|
||||
{
|
||||
return { data() + size() - Count, Count };
|
||||
}
|
||||
|
||||
template<std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||
constexpr Span<element_type, Count> subspan() const
|
||||
{
|
||||
return { data() + Offset, Count == dynamic_extent ? size() - Offset : Count };
|
||||
}
|
||||
|
||||
constexpr Span<element_type, dynamic_extent>
|
||||
subspan(std::size_t Offset, std::size_t Count = dynamic_extent) const
|
||||
{
|
||||
return { data() + Offset, Count == dynamic_extent ? size() - Offset : Count };
|
||||
}
|
||||
|
||||
private:
|
||||
pointer data_;
|
||||
size_type size_;
|
||||
};
|
||||
|
||||
}; /* namespace libcamera */
|
||||
|
||||
#endif /* __LIBCAMERA_SPAN_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue