[libcamera-devel] [PATCH 13/23] libcamera: span: Add support for STL containers

Jacopo Mondi jacopo at jmondi.org
Mon Jan 13 17:42:35 CET 2020


From: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

Add support for STL containers to the Span class implementation and
make it fully C++20-compliant.

Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
 include/libcamera/span.h | 187 +++++++++++++++++++++++++++++++--------
 src/libcamera/span.cpp   | 115 ------------------------
 2 files changed, 152 insertions(+), 150 deletions(-)

diff --git a/include/libcamera/span.h b/include/libcamera/span.h
index 3e63603f60ed..0fffad3a99db 100644
--- a/include/libcamera/span.h
+++ b/include/libcamera/span.h
@@ -9,79 +9,196 @@
 #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, size_t Extent = dynamic_extent>
+class Span;
+
 template<typename T>
-class Span
+class Span<T, dynamic_extent>
 {
 private:
+	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 {
+	};
+
+	template<bool B, class U = void>
+	using enable_if_t = typename std::enable_if<B, U>::type;
+
+	template<typename U>
+	using remove_pointer_t = typename std::remove_pointer<U>::type;
+
+public:
+	using element_type = T;
+	using value_type = typename std::remove_cv<T>::type;
+	using size_type = std::size_t;
+	using different_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>;
 
-	class Storage
+	static constexpr std::size_t extent = dynamic_extent;
+
+	constexpr Span() noexcept
+		: data_(nullptr), size_(0)
 	{
-	public:
-		Storage(T *ptr, size_t size)
-			: ptr_(ptr), size_(size)
-		{
-		}
+	}
 
-		T *ptr() const { return ptr_; }
-		size_t size() const { return size_; }
+	constexpr Span(pointer ptr, size_type count)
+		: data_(ptr), size_(count)
+	{
+	}
 
-	private:
-		T *ptr_;
-		size_t size_;
-	};
+	constexpr Span(pointer first, pointer last)
+		: data_(first), size_(last - first)
+	{
+	}
 
-public:
-	Span(T &v)
-		: storage_(&v, 1)
+	template<std::size_t N>
+	constexpr Span(element_type (&arr)[N],
+		       enable_if_t<std::is_convertible<remove_pointer_t<decltype(arr)> (*)[],
+						       element_type (*)[]>::value,
+				   std::nullptr_t> = nullptr) noexcept
+		: data_(arr), size_(N)
 	{
 	}
 
-	Span(const T &v)
-		: storage_(const_cast<T *>(&v), 1)
+	template<std::size_t N>
+	constexpr Span(std::array<value_type, N> &arr,
+		       enable_if_t<std::is_convertible<remove_pointer_t<decltype(arr.data())> (*)[],
+						       element_type (*)[]>::value,
+				   std::nullptr_t> = nullptr) noexcept
+		: data_(arr.data()), size_(N)
 	{
 	}
 
-	Span(T *v, size_t s)
-		: storage_(v, s)
+	template<std::size_t N>
+	constexpr Span(const std::array<value_type, N> &arr) noexcept
+		: data_(arr.data()), size_(N)
 	{
 	}
 
-	Span(const T *v, size_t s)
-		: storage_(const_cast<T *>(v), s)
+	template<class Container>
+	constexpr Span(Container &cont,
+		       enable_if_t<!is_span<Container>::value &&
+				   !is_array<Container>::value &&
+				   !std::is_array<Container>::value &&
+				   std::is_convertible<remove_pointer_t<decltype(cont.data())> (*)[],
+						       element_type (*)[]>::value,
+				   std::nullptr_t> = nullptr)
+		: data_(cont.data()), size_(cont.size())
 	{
 	}
 
-	Span(std::initializer_list<T> list)
-		: storage_(const_cast<T *>(list.begin()), list.size())
+	template<class Container>
+	constexpr Span(const Container &cont,
+		       enable_if_t<!is_span<Container>::value &&
+				   !is_array<Container>::value &&
+				   !std::is_array<Container>::value &&
+				   std::is_convertible<remove_pointer_t<decltype(cont.data())> (*)[],
+						       element_type (*)[]>::value,
+				   std::nullptr_t> = nullptr)
+		: data_(cont.data()), size_(cont.size())
 	{
 	}
 
-	Span(const Span &other) = default;
-	Span &operator=(const Span &other) = default;
+	template<class U, std::size_t N>
+	constexpr Span(const Span<U, N> &s,
+		       enable_if_t<std::is_convertible<U (*)[], element_type (*)[]>::value,
+				   std::nullptr_t> = nullptr) noexcept
+		: data_(s.data()), size_(s.size())
+	{
+	}
 
-	T *data() const { return storage_.ptr(); }
-	size_t size() const { return storage_.size(); }
+	constexpr Span(const Span &other) noexcept = default;
 
-	T &operator[](unsigned int index) const
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconstexpr-not-const"
+	constexpr Span &operator=(const Span &other) noexcept
 	{
-		if (index >= size())
-			return *(end() - 1);
-		return *(data() + index);
+		return *this, data_ = other.data_, size_ = other.size_;
 	}
+#pragma GCC diagnostic pop
 
 	constexpr iterator begin() const { return data(); }
-	constexpr iterator cbegin() const { return begin(); }
+	constexpr const_iterator cbegin() const { return begin(); }
 	constexpr iterator end() const { return data() + size(); }
-	constexpr iterator cend() const { return end(); }
+	constexpr const_iterator cend() const { return end(); }
+	constexpr reverse_iterator rbegin() const { return data() + size() - 1; }
+	constexpr const_reverse_iterator crbegin() const { return rbegin(); }
+	constexpr reverse_iterator rend() const { return 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, dynamic_extent> 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:
-	Storage storage_;
+	pointer data_;
+	size_type size_;
 };
 
 }; /* namespace libcamera */
diff --git a/src/libcamera/span.cpp b/src/libcamera/span.cpp
index 72ffdf7481c4..43391b29ec85 100644
--- a/src/libcamera/span.cpp
+++ b/src/libcamera/span.cpp
@@ -7,122 +7,7 @@
 
 #include <libcamera/span.h>
 
-/**
- * \file span.h
- * \brief libcamera implementation of C++20 std::span<>
- */
-
 namespace libcamera {
 
-/**
- * \class Span
- * \brief Representation of a sequence of contiguous objects of type T
- *
- * This class represents a sequence of fixed size of contiguous objects of
- * template type T with the first object residing in position 0.
- *
- * A Span internally consists of a pointer to raw memory and an associated
- * number of elements there located. It does not enforce any ownership on the
- * memory it represents, but it only provides a convenient, lightweight and
- * easily transportable view on such memory area.
- *
- * A Span can be constructed from a single element as well as from raw memory
- * by providing an associated size. It can be accessed by index and iterated
- * as a regular standard library container. As Span does not enforce any memory
- * ownership, destroying a Span instance does not invalidate the memory it
- * represents.
- *
- * The libcamera implementation of Span it's a simplified implementation of
- * C++20 the std::span<> class and it is no 1-to-1 compatible with it. Care
- * should be taken in not mixing usage of the two classes.
- */
-
-/**
- * \fn Span::Span(T &v)
- * \brief Contruct a Span of size 1 representing element \a v
- * \param[in] v The element represented by the Span
- */
-
-/**
- * \fn Span::Span(const T &v)
- * \brief Contruct a Span of size 1 representing the constant element \a v
- * \param[in] v The constant element represented by the Span
- */
-
-/**
- * \fn Span::Span(T *v, size_t s)
- * \brief Contruct a Span of size \a s representing elements in memory \a v
- * \param[in] v The memory area represeted by the Span
- * \param[in] s The number of elements in memory area \a v
- */
-
-/**
- * \fn Span::Span(const T *v, size_t s)
- * \brief Contruct a Span of size \a s representing elements in constant memory \a v
- * \param[in] v The constant memory area represeted by the Span
- * \param[in] s The number of elements in memory area \a v
- */
-
-/**
- * \fn Span::Span(std::initializer_list<T> list)
- * \brief Contruct a Span with an initialier list of elements
- * \param[in] list The initializer list
- */
-
-/**
- * \fn Span::Span(const Span &other)
- * \brief Contruct a Span with the content of \a other
- * \param[in] other The other Span
- */
-
-/**
- * \fn Span::operator=(const Span &other)
- * \brief Replace the content of the Span with the one from \a other
- * \param[in] other The other Span
- */
-
-/**
- * \fn Span::data()
- * \brief Retrieve a pointer to the beginning of the memory area represented by
- * the Span
- * \return A pointer to the raw memory area
- */
-
-/**
- * \fn Span::size()
- * \brief Retrieve the number of elements in the Span
- * \return The number of elements in the Span
- */
-
-/**
- * \fn Span::operator[](unsigned int index)
- * \brief Retrieve element in position \a index
- * \param[in] index
- *
- * If \a index is larger than the number of elements in the Span, the last
- * element is returned.
- *
- * \return The element at position \a index
- */
-
-/**
- * \fn iterator Span::begin()
- * \brief Retrieve an iterator to the first element in the Span
- */
-
-/**
- * \fn const_iterator Span::cbegin()
- * \brief Retrieve a constant iterator to the first element in the Span
- */
-
-/**
- * \fn iterator Span::end()
- * \brief Retrieve an iterator pointing to the past-the-end element in the Span
- */
-
-/**
- * \fn const_iterator Span::cend()
- * \brief Retrieve a constant iterator pointing to the past-the-end element in the Span
- */
 
 } /* namespace libcamera */
-- 
2.24.0



More information about the libcamera-devel mailing list