summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo@jmondi.org>2020-01-02 11:17:39 +0100
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-03-06 18:08:37 +0200
commit09ab21b85ad83243878dab898eb0a6d0e85e6780 (patch)
treec9c001bdcc15f47ef7d96e28cfdceae6852f5e46
parentdd9429f438865c5a48b460b4ce33b3f74f90027f (diff)
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>
-rw-r--r--Documentation/Doxyfile.in3
-rw-r--r--include/libcamera/meson.build1
-rw-r--r--include/libcamera/span.h417
3 files changed, 420 insertions, 1 deletions
diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in
index beeaf6d3..d5ba5c4e 100644
--- a/Documentation/Doxyfile.in
+++ b/Documentation/Doxyfile.in
@@ -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 \
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index f58c02d2..f47c583c 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -14,6 +14,7 @@ libcamera_api = files([
'pixelformats.h',
'request.h',
'signal.h',
+ 'span.h',
'stream.h',
'timer.h',
])
diff --git a/include/libcamera/span.h b/include/libcamera/span.h
new file mode 100644
index 00000000..513ddb43
--- /dev/null
+++ b/include/libcamera/span.h
@@ -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__ */