From patchwork Sat Feb 29 16:42:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 2919 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8D14A62689 for ; Sat, 29 Feb 2020 17:43:22 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1216DA28; Sat, 29 Feb 2020 17:43:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1582994602; bh=ptdAb66FWFDwGE6nwbpVByCYnUyXRaVwFUb9/1L+ctM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eeHqfBeA/vBGdD4Ile8vrAleDRfbqKya/yK4Nr3fKJpWX9Z13XuUaZH634tM/yGRy QwhnYU3i9jXEcna973HwJTK10kfchUOGqw/qfw8slM1/Tah2dZjmAYU16ZubB02IYr rhiP6n85sJYewWrLGv3h0nSC5CgpxzSc0Ov7N5Cc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Sat, 29 Feb 2020 18:42:24 +0200 Message-Id: <20200229164254.23604-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200229164254.23604-1-laurent.pinchart@ideasonboard.com> References: <20200229164254.23604-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/31] libcamera: Add a C++20-compliant std::span<> implementation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 29 Feb 2020 16:43:22 -0000 From: Jacopo Mondi C++20 will contain a std::span<> class that represents a contiguous sequence of objects. Its main purpose is to group array pointers and size together in APIs. Add a compatible implementation to the utils namespace. This will be used to implement array controls. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Acked-by: Kieran Bingham --- Documentation/Doxyfile.in | 4 +- include/libcamera/meson.build | 1 + include/libcamera/span.h | 417 ++++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/span.cpp | 12 + 5 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 include/libcamera/span.h create mode 100644 src/libcamera/span.cpp diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index beeaf6d3cf48..457e23a086a2 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -840,8 +840,10 @@ 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/span.cpp \ @TOP_SRCDIR@/src/libcamera/include/device_enumerator_sysfs.h \ @TOP_SRCDIR@/src/libcamera/include/device_enumerator_udev.h \ @TOP_SRCDIR@/src/libcamera/pipeline/ \ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index f58c02d2cf35..f47c583cbbc0 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 000000000000..513ddb432405 --- /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 +#include +#include +#include +#include + +namespace libcamera { + +static constexpr std::size_t dynamic_extent = std::numeric_limits::max(); + +template +class Span; + +namespace details { + +template +struct is_array : public std::false_type { +}; + +template +struct is_array> : public std::true_type { +}; + +template +struct is_span : public std::false_type { +}; + +template +struct is_span> : public std::true_type { +}; + +} /* namespace details */ + +namespace utils { + +template +constexpr auto size(const C &c) -> decltype(c.size()) +{ + return c.size(); +} + +template +constexpr auto data(const C &c) -> decltype(c.data()) +{ + return c.data(); +} + +template +constexpr auto data(C &c) -> decltype(c.data()) +{ + return c.data(); +} + +template +constexpr T *data(T (&array)[N]) noexcept +{ + return array; +} + +template +struct tuple_element; + +template +struct tuple_element> { + using type = T; +}; + +template +struct tuple_size; + +template +struct tuple_size> : public std::integral_constant { +}; + +template +struct tuple_size>; + +} /* namespace utils */ + +template +class Span +{ +public: + using element_type = T; + using value_type = typename std::remove_cv_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; + using const_reverse_iterator = std::reverse_iterator; + + static constexpr std::size_t extent = Extent; + + template> + constexpr Span() noexcept + : data_(nullptr) + { + } + + constexpr Span(pointer ptr, size_type count) + : data_(ptr) + { + } + + constexpr Span(pointer first, pointer last) + : data_(first) + { + } + + template + constexpr Span(element_type (&arr)[N], + std::enable_if_t (*)[], + element_type (*)[]>::value && + N == Extent, + std::nullptr_t> = nullptr) noexcept + : data_(arr) + { + } + + template + constexpr Span(std::array &arr, + std::enable_if_t (*)[], + element_type (*)[]>::value && + N == Extent, + std::nullptr_t> = nullptr) noexcept + : data_(arr.data()) + { + } + + template + constexpr Span(const std::array &arr, + std::enable_if_t (*)[], + element_type (*)[]>::value && + N == Extent, + std::nullptr_t> = nullptr) noexcept + : data_(arr.data()) + { + } + + template + constexpr Span(Container &cont, + std::enable_if_t::value && + !details::is_array::value && + !std::is_array::value && + std::is_convertible (*)[], + element_type (*)[]>::value, + std::nullptr_t> = nullptr) + : data_(utils::data(cont)) + { + } + + template + constexpr Span(const Container &cont, + std::enable_if_t::value && + !details::is_array::value && + !std::is_array::value && + std::is_convertible (*)[], + element_type (*)[]>::value, + std::nullptr_t> = nullptr) + : data_(utils::data(cont)) + { + static_assert(utils::size(cont) == Extent, "Size mismatch"); + } + + template + constexpr Span(const Span &s, + std::enable_if_t::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 + constexpr Span first() const + { + static_assert(Count <= Extent, "Count larger than size"); + return { data(), Count }; + } + + constexpr Span first(std::size_t Count) const + { + return { data(), Count }; + } + + template + constexpr Span last() const + { + static_assert(Count <= Extent, "Count larger than size"); + return { data() + size() - Count, Count }; + } + + constexpr Span last(std::size_t Count) const + { + return { data() + size() - Count, Count }; + } + + template + constexpr Span 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 + 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 +class Span +{ +public: + using element_type = T; + using value_type = typename std::remove_cv_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; + using const_reverse_iterator = std::reverse_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 + constexpr Span(element_type (&arr)[N], + std::enable_if_t (*)[], + element_type (*)[]>::value, + std::nullptr_t> = nullptr) noexcept + : data_(arr), size_(N) + { + } + + template + constexpr Span(std::array &arr, + std::enable_if_t (*)[], + element_type (*)[]>::value, + std::nullptr_t> = nullptr) noexcept + : data_(utils::data(arr)), size_(N) + { + } + + template + constexpr Span(const std::array &arr) noexcept + : data_(utils::data(arr)), size_(N) + { + } + + template + constexpr Span(Container &cont, + std::enable_if_t::value && + !details::is_array::value && + !std::is_array::value && + std::is_convertible (*)[], + element_type (*)[]>::value, + std::nullptr_t> = nullptr) + : data_(utils::data(cont)), size_(utils::size(cont)) + { + } + + template + constexpr Span(const Container &cont, + std::enable_if_t::value && + !details::is_array::value && + !std::is_array::value && + std::is_convertible (*)[], + element_type (*)[]>::value, + std::nullptr_t> = nullptr) + : data_(utils::data(cont)), size_(utils::size(cont)) + { + } + + template + constexpr Span(const Span &s, + std::enable_if_t::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 + constexpr Span first() const + { + return { data(), Count }; + } + + constexpr Span first(std::size_t Count) const + { + return { data(), Count }; + } + + template + constexpr Span last() const + { + return { data() + size() - Count, Count }; + } + + constexpr Span last(std::size_t Count) const + { + return { data() + size() - Count, Count }; + } + + template + constexpr Span subspan() const + { + return { data() + Offset, Count == dynamic_extent ? size() - Offset : Count }; + } + + constexpr Span + 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__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 88658ac563f7..2448f0e96468 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -36,6 +36,7 @@ libcamera_sources = files([ 'request.cpp', 'semaphore.cpp', 'signal.cpp', + 'span.cpp', 'stream.cpp', 'thread.cpp', 'timer.cpp', diff --git a/src/libcamera/span.cpp b/src/libcamera/span.cpp new file mode 100644 index 000000000000..753104765cea --- /dev/null +++ b/src/libcamera/span.cpp @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * span.h - C++20 std::span<> implementation for C++11 + */ + +#include + +namespace libcamera { + +} /* namespace libcamera */